Vue是一套用于 构建用户界面 的 渐进式 JavaScript框架。
渐进式:vue可以自底向上逐层的应用(简单应用:只需一个轻量小巧的核心库;复杂应用:可以引入各种Vue插件库)
一、Vue基础
1.1. v-bind与v-model
v-bind:单项数据绑定,model => view view !=> medel
v-model:双向数据绑定,model <=> view (仅用于表单元素的value)
简写:
1.2.回顾Object.defineProperty
Object.defineProperty:对对象的属性进行操作(vue2.0中的数据劫持、数据代理...底层都有用到)
1.3. vue中的数据代理
数据代理:通过一个对象(vm)对另一个对象(data)的属性进行操作(Object.defineProperty)
1.4. Vue中的事件
a.事件传参问题
@click="fn" 与@click="fn($event,x)" 都可调用事件,后者可直接传递参数
b.事件修饰符(6种)
c.键盘事件
注:tab及系统修饰键(ctrl、alt、shift、meta)建议搭配@keydown.键名 使用
1.5. 计算属性computed 与 监视/侦听属性watch
计算属性:通过已有属性计算得来的新属性(getter/setter——defineProperty)
优点:计算属性computed有缓存,当创建时/所依赖的属性发生变化时才会刷新
监视属性:当监视的属性发生变换时被调用(handler(newVal,oldVal){})
计算属性与监视属性的区别:
当计算属性和监视属性都能实现效果时优先选择计算属性,但涉及到一些异步(比如:定时器setTimeout...)操作的就选监视属性。因为,computed依靠函数的返回值,不能开启异步任务,而watch依靠自身计算不依靠返回结果,可以开启异步任务。
1.6. 样式绑定
a.绑定class样式
字符串写法:适用于样式的类名不确定,需要动态绑定
:class="variable"
数组写法:适用于要绑定的样式个数不确定,名字也不确定
:class="classArr"
对象写法:适用于要绑定的样式个数确定,名字也确定,但要动态决定是否使用
:class="classObject"
b.绑定style样式
对象写法:
:style="styleObj"
注意:styleObj里要使用小驼峰命名
对象写法(不常用):
:style="[styleObj1,styleObj2]" :style="styleArr"
1.7. 条件渲染(v-if v-else v-show)
v-show="true/false" ======底层实现就是控制display
v-if="true/false" =======为false时直接对元素进行删除操作
注:切换频率高,使用v-show,频率低,使用v-if
v-if、v-else-if、v-else配合使用,当某条语句的判断条件成立时,紧接在该语句后的其他判断语句就不执行。
这几个条件配合使用时,这几条语句中间不可以加入其他语句,否则该判断结构会被打断,会失效。
注:template标签不会破坏DOM结构,但template只能配合v-if使用
1.8. 列表渲染(v-for)
//person=[
{id:'001',name:'张三'},
{id:'002',name:'李四'},
{id:'003',name:'王五'}
]
{{p.name}}
v-for中key的原理与作用:
真实dom没有key,虚拟dom上有,用户操作是在真实dom上发生,用户操作真实dom后,虚拟dom也随之发生改变,在进行页面渲染之前,新旧虚拟dom会进行对比(diff算法),根据key进行对比,key相同的元素,数据也相同的话就直接复用,否则就重新生成。使用index作为key的值,当打乱遍历的数据顺序时(如:unshift添加数据),数据会发生错乱,所以,开发中最好使用数据的唯一标识作为key的值。
key是每个节点的唯一标识,在vue中不写不会报错,但在react中会报错。
扩展:for-in与for-of的区别:
for-in主要用于遍历对象(val,key,inedx),也可以遍历数组(val,index)
for-of(es6新特性)主要用于遍历数组,也可以遍历字符串、伪数组,一般不用于遍历对象(需内建Object.keys())
使用总结:对象遍历使用for-in,数组遍历使用for-of
列表过滤:
方法一:在watch中使用filter(需要新建一个data属性作为遍历的对象,原数据对象不能直接修改)
方法二:在computed中使用filter
注意:data中的原数据尽量不要直接修改
列表排序:
在computed中利用filter+sort实现:
1.9. Vue监测数据改变的原理:
当data中的数据发生改变时,Observer方法(观察者)会收集数据,触发该数据对应的set方法(setter),setter会重新解析模板(界面),形成新的虚拟dom树,新旧虚拟dom树进行对比,相同的的元素直接复用,不一样的元素进行生成创建,达到监听数据改变形成响应式的功能。
Vue.set的使用:
①.在向data中的 对象 追加数据时,不可以直接添加(无法实现响应式),需要使用Vue.set()。
Vue.set(需要添加数据的对象,key,value)
或者 this.$set(需要添加数据的对象,key,value)
缺陷:不能直接给data追加数据,只能给data中的对象添加
②.在Vue中,没有为数组提供getter和setter,根据索引值直接赋值修改data中的数组数据,页面数据不会响应,Vue对数组的常用方法进行了封装,所以只有调用数组方法修改数组时,响应才会生效。
1.10. 收集表单数据(form)
表单type属性:
text:文本(v-model.trim收集数据时去除空格)
password:密码
number:数值(input默认输入的是字符串,所以,可以v-model.numder)
radio:单选(多选一时,固定name属性)===>配置value值,被选中时读取value
checkbox:多选 (多选v-model要绑定数组)===>配置value值,被选中时读取value
select>option:下拉选项
textarea:多行文本输入(有时不需要打一个字就收集,可以v-model.lazy,改标签失去焦点时才收集)
单个checkbox:勾选框(直接指定v-model,无需配置value值)
1.11. 过滤器
数据 | 过滤器的名称
过滤器的本质就是一个函数,将数据作为参数传入过滤器,然后将返回结果替换整个过滤器。多个过滤器可以串联使用。过滤器不改变原数据。
过滤器一般用于插值语法{{}}和v-bind,不能用于v-model
局部过滤器:和methods、methods一样,直接在Vm下filters:{}
//局部过滤器
filters:{
过滤器名(数据,参数='设置参数默认值'){
代码片段;
return 返回结果
}
}
全局过滤器:Vue.filter('过滤器名称',function(){})
//全局过滤器
Vue.filter('mySlice',function(value){
return value.slice(0,4)
})
总结:
1.12. 内置指令(Vue提供的但不常用的指令)
复习:
v-bind: 单向绑定解析表达式, 可简写为 :xxx
v-model : 双向数据绑定
v-for : 遍历数组/对象/字符串
v-on : 绑定事件监听, 可简写为@
v-if : 条件渲染(动态控制节点是否存存在)
v-else : 条件渲染(动态控制节点是否存存在)
v-show : 条件渲染 (动态控制节点是否展示)
v-text指令:
1.作用:向其所在的标签中插入文本内容。
2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。
v-html指令:
1.作用:向指定节点中渲染包含html结构的内容。
2.与插值语法的区别:
(1).v-html会替换掉节点中所有的内容,{{xx}}则不会。
(2).v-html可以识别html结构。
3.严重注意:v-html有安全性问题!!!!
(1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
(XSS攻击:冒充用户攻击,盗用cookie)
(2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!
扩展:cookie的工作原理:
v-cloak指令(没有值):
1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。
扩展:JS阻塞:JS具有阻塞特性,当浏览器在执行js代码时,不能同时做其它事情,即
文件暴露/导出的三种方式:
1、分别暴露:export const 组件名 = Vue.extend({})
2、统一暴露:export {组件名} ---------引入时:import {***} from ****
3、默认暴露:export default 组件名---------引入时:import *** from ****
统一暴露与默认暴露的区别
App.vue 汇总所有的组件
main.js 入口文件(new Vue({}))====引入App.vue
index.html 入口文件的容器====引入main.js
三、Vue脚手架 Vue CLI(command line interface 命令行接口工具)
Vue脚手架是Vue官方提供的标准化开发工具/开发平台。
3.1.Vue脚手架
使用步骤:
①全局安装@vue/cli(仅一次使用时,记得配置淘宝镜像)
npm config set registry https://registry.npm.taobao.org
②切换到要创建项目的目录,然后使用命令行创建项目 vue create ***
③启动项目 npm run serve
注:Vue脚手架隐藏了所有webpack相关的配置,若想查看相关配置:vue inspect > output.js
可参考文章使用Vue-CLI搭建项目
项目结构解析:
总结:执行npm run serve=>main.js=>App.js=>执行其下的组价=>汇总到App.js=>找到容器所在文件index.html,将执行的内容放入容器,浏览器进行渲染。
针对main.js中的render方法进行分析:
完整版的vue:vue核心+模板解析器,其中模板解析器占1/3左右,如果使用完整版的vue,使用webpack打包后模板解析器占了很大内存且无用。为了使打包完成的项目体积小一些,脚手架中引入的vue是残缺的,没有模板解析器(无法解析template标签),就需要使用render函数来进行渲染。
render其实是一个函数:
render(createElement){
return createElement('h1','你好啊!')
}
//vue调用,且该函数中没有用到this,可以简写:
render:createElement=>createElement('h1','你好啊!')
脚手架默认配置:public、favicon.icn、index.html、src、main.js
默认配置一般是不可更改的,若要自定义个性化配置,可在项目的package.json的同级目录下创建vue.config.js文件(若修改该文件,一定要有重启项目)。
关闭语法检查的方法:在vue.config.js文件下添加 lintOnSave:false(与pages平级)
Vue脚手架总结:
3.2. ref属性
普通标签:在原生javascript中,我们获取一个html元素通常使用id属性(getElementById),但在vue中,我们使用ref属性给元素做标识,然后this.$refs.获取相应元素。
组件标签:当ref使用到组件标签上时,this.$refs.获取到得就是该组件的实例对象VueComponent。(可用于组件间通信)
3.3. props配置
①<组件标签 key1="value1" key2="value2" ...>
组件:props:["key1","key2",...],
但这样接收到的是字符串,所以,可以使用v-bind解决,②即:<组件标签 :key1="value1" :key2="value2" ...>,为了避免上述情况,接收时也可进行类型限制,即:props:{key1:String,key2:Number,...}。③也可设置默认值指定和必要性限制:props:{key1:{type:String,required:true},key2:{type:Number,default:77},...}。
注意:接收到的props是不可以更改的,若想修改,可以赋值给其他变量,然后修改。扫描优先级:props>data
e.g.
props总结:
3.4. mixin混入(混合)
mixin:多个组件使用相同的配置时使用。
mixin总结:
3.5. 插件plugin
在src文件夹下创建文件plugins.js文件,创建一个对象(插件的本质是一个对象),在该对象的install方法(一定要有install方法)中进行插件编写,记得暴露/导出,然后在main.js中引入,然后使用(Vue.use(插件名,参数列表))。
3.6. scoped样式
在Vue中,各个组件的样式最终是会汇总到一起的,在各个组件中可能会出现类名相同的情况,造成类名冲突。为了解决上述问题,可以给各个组件的样式标签style加一个作用域限制(scoped)。
注意:App组件不适用scoped
总结:让样式在局部生效,防止冲突
组件间通信:
原始方法:
父子间传参
兄弟间传参:借助父组件
1、自定义事件
2、全局事件总线
3、消息订阅与发布
4、Vuex
5、路由传参
3.7. 本地存储(控制台=>Application)
1、localStorage:借助浏览器的本地存储,将数据存在硬盘上。关闭浏览器,数据不会消失。
(主动删除或者删除浏览器缓存时就会被清除)
注:localStorage解决页面更新,数据丢失问题
localStorage.setItem("key":"value");//存储,key和value都要使用字符串
localStorage.getItem("key");//读取
localStorage.removeItem("key");//移除
localStorage.clear();//清空
JSON.stringify();//数组对象转JSON字符串
JSON.parse();//
2、sessionStorage:关闭浏览器,数据消失
3.8. 组件自定义事件
子组件给父组件传递数据的方式(3种):
1、通过父组件给子组件传递函数类型的props实现:子组件通过props接收,然后通过函数使用触发将数据传递给父组件。
2、通过父组件给子组件绑定一个自定义事件实现:给谁绑的自定义事件找谁触发,使用this.$emit("事件名",参数)触发(第一种写法,使用@或v-on
3、通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法,使用ref)
解绑自定义事件(给谁绑的自定义事件找谁解绑):
1、this.$off('自定义事件名'):解绑一个
2、this.$off(['自定义事件名','自定义事件名']):解绑多个
3、this.$off():解绑所有自定义事件
注意:销毁当前组件的VueComponent实例,销毁后该组件上的所有自定义事件都失效。
3.9. 全局事件总线:任意组件间通信
全局事件总线:在A组件中给x绑定自定义事件demo,回调函数留在A中,B组件触发x中的事件demo,并传递参数p,A组件就可接收到B组件传递的参数p。
x应满足的条件:所有组件都可访问;可调用到$on/$off/$emit...
条件①:所有组件都可访问
一个重要的内置关系:VueComponent.prototype.prop===Vue.prototype(让组件实例对象vc可以访问到Vue原型上的属性和方法),所以,可以把X放到Vue的原型对象Vue.prototype上(在main.js文件中)。
条件②:可调用到$on/$off/$emit...
在数据监测、数据代理之前(beforeCreate)直接安装(main.js)
new Vue({
el:'#app',
render: h => h(App),
beforeCreate() {
//Vue.prototype.x= this
Vue.prototype.$bus = this //安装全局事件总线
}
})
使用:
this.$bus.$on('自定义事件名',(data)=>{data:接收到的数据})
this.$bus.$emit(('事件名',传递的数据)
this.$off('事件名');解绑
注:
1、收数据的组件:在mounted中绑定事件总线中自定义事件:this.$bus.on('绑定的自定义事件',绑定时触发的函数);
传数据的组件:触发this.$bus.$emit('绑定的自定义事件',参数);
2、在组件销毁前,可以关闭该组件使用到的自定义事件;
e.s. beforDestroy(){this.$bus.$off('hello')}
3.10. 消息订阅与发布:任意组件间通信
消息订阅与发布(mounted中):
(推荐库pubsub-js)安装:npm i pubsub-js
引入:import pubsub- from ' pubsub-js'
1.订阅消息:消息名(接收数据的组件:需要/买):
this.pubId=pubsub.subscribe('消息名',(消息名msgName,数据data)=>{})
//第二个参数使用箭头函数,this才能指向VC(组件实例对象)
2.发布消息:消息内容(传递数据的组件:提供/卖)pubsub.publish('消息名',function(){ return ...})
注:组件销毁前(beforeDeatory)需要把订阅消息取消pubsub.unsubscribe(this.pubId);
消息订阅与发布原生不可实现,需要借助第三方库pubsub-js(其他库也可以)
$nextTick
语法:this.$nextTick(function(){})
作用:在下一次DOM更新结束后执行其指定的回调函数。
什么时候用:当改变数据后,要基于更新后的DOM进行某些操作,要在nextTick所指定的回调函数中执行。
3.11. 过渡与动画
1、单个元素:将产生动画效果的这个元素使用标签
要使元素一开始就有进入动画,给transition标签加appear属性。
当有多个transition时,可以给transition标签加name属性(name="x1")进行区分,但在写选择器时,选择器名得与之对应,进入.x1-enter-active 离开:x1-leave-active
2、多个元素使用相同的动画效果:使用
你好啊!
使用动画:
使用过渡:
推荐:动画库animate
多个元素使用同一个动画效果(这里使用了动画库):
你好啊!
尚硅谷!
3.12. 配置代理
axios:promis风格,支持请求拦截和响应拦截,体积小
fetch:会把返回的数据包装两层promise,兼容性差
1、axios的使用:(使用广泛,推荐)
下载:npm i axios
引入:import axios from 'axios'(App.vue)
使用:axios.get('url').then(response=>{},err=>{})
解决跨域(协议名+主机名+端口号):
1、cors:后端配置特殊的响应头
2、jsonp:借助script的src属性在引入外部资源时不受同源策略限制(只能解决get产生的跨域问题)
3、代理服务器(开发中常用)
使用脚手架中的代理服务器:
方式一:
在vue.config.js配置devServer:{ proxy:'http://localhonst:5000}
缺点:只能配置一台服务器代理;无法灵活控制请求是否走代理
方式二:
devServer:{
proxy:{
'/请求前缀':{
target:'url',//要发送到的服务器
pathRewirite:{'^/请求前缀',''},//重写路径(一定要写!!)
ws:true,//用于支持websocket
changeOrigin:false//用于控制请求头中的host值
}
}
}
axios.get('http://host:端口号/前缀/路径')
注意:
1、所谓“前缀”在请求时是放在端口号之后
2、引入第三方文件时,①src-assets-...-在App.vue中引入 import '文件' ②在public中添加,然后在index.html文件中使用link引入
3、Vue的插件库vue-resource(维护频率低)
安装:npm i vue-resource
引入(main.js):import vueResource from 'vue-resource'
使用:Vue.use(vueResource)
e.g. this.\$http.get('url').then()
3.13. 插槽slot
插槽:让父组件可以向子组件指定的位置插入html结构,也是一种组件间通信的方式,适用于父子组件。[子组件挖坑等父组件来填(父组件不填时使用默认值)]
插槽/匿名插槽/具名插槽/作用域插槽/v-slot指令
四、Vuex
4.1. Vuex简介
Vuex:专门在Vue中实现集中式状态(数据)管理的一个Vue插件,对Vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
Vuex
使用场景:[共享数据]①多个组件依赖同一状态/数据 ②来自不同组件的行为需要变更同一状态
4.2. Vuex工作原理
Vuex=Actions+Mutations+State
Actions:动作、行为 Mutations:修改、加工、维护 State:状态、数据
所有的组件实例对象VueCompontent都要能使用store(import+use)
注意:vue2只能使用vuex的3版本,vue3只能使用vuex的4版本
4.3. 搭建Vuex环境
1、安装:npm i vuex@指定版本号
2、引入(main.js):import Vuex from 'vuex'
Vue.use(Vuex)
3、store
4、VueComponent都能使用store
创建文件:src=>store=>index.js
//该文件用于创建Vuex中最为核心的stroe
//引入Vuex
import Vuex from 'vuex'
//准备actions——用于响应组件中的动作(服务员)
const actions = {}
//准备mutations——用于操作数据(state)
const mutations = {}
//准备state——用于存储数据
const state = {}
//创建store
//const store = new Vuex.Store({
export default new Vuex.Store({
acrions,
mutations,
state
})
//导出/暴露文件
//export default store
然后在main.js中引入 import store from './store/index.js',在vm中使用
注意:因为store是基于Vuex的,所以store必须得Vuex生效后才能使用,但import的执行顺序总是大于Vue.use(),所以,在./store/index.js中引入Vuex,然后将Vue.use(Vuex)放到store的创建之前,记得删除main.js中Vuex的引入和使用。
总结:
1获取state中的数据:this.$store.state.数据名
2修改state中的共享数据: 1
①将共享数据放到state中;
②在组件中调用this.$store.dispatch("数据名",变量);
③在actions中编写对应的数据 数据名:function(context,value){context.commit('数据名',value)},(actions可以进行业务逻辑的操作,尤其是对各组件共同使用到的操作,需要的数据去content中找);
④在mutations中** 数据名:function(state,value){}**,mutations尽量不要进行业务逻辑的操作,也不要发送请求。
无业务逻辑处理时,可忽略③步骤,①步骤中直接调用④步骤,即this.$store.commit("数据名",变量)
4.4. getters配置项
getters配置项:用于将state中的数据进行加工
4.5. 4种map方法的使用(读取Vuex中的数据的方法)
1、this.$store.state.数据名
2、借助mapState生成计算属性,从state中读取数据(对象写法)
...mapState({计算属性名:需获取的state中的变量,...})
3、借助mapState生成计算属性,从state中读取数据(数组写法):计算属性名与需获取的state中的变量同名时
...mapState(['需获取的state中的变量',...])
同理:还有mapGetters方法、mapActions方法、mapMutations方法(加上mapState方法,总的4个,mapActions和mapMutations在调用时,记得把变化量作为参数传入的)
多组件共享数据:
4.5. Vuex模块化namespace
Vuex模块化:按功能分类集中处理
配置项处理:
注意:每一个模块一定要开启命名空间'namespace:true'
组件获取数据时:
自己写:this.$store.state.模块名.数据名 this.$store.commit('模块名/mutation名',变化量名)
this.$store.state.getters[模块名/数据名] this.$store.state.dispatch('模块名/mutation名',变化量名)
借助map**方法:...mapState('模块名',{'方法名':数据,...})/...mapState('模块名',['数据列表']),同理,mapGetters方法、mapActions方法、mapMutations方法也一样
总结:
五、路由
路由:一个路由(route)就是一组映射关系【key-value(路径-组件)】,将路径与组件配对使用,多个路由需要路由器(router)进行管理。
5.1. 路由的基本使用
1、安装vue-router:npm i vue-router
(2022.7月之后,默认版本为4,且4版本只能在vue3中使用,若是vue2项目,使用路由安装时需要指定版本3:npm i vue-router@3
)
2、在mian.js中引入使用:import VueRouter from 'vue-router'
Vue.use(VueRouter)
3、创建路由器:在src下创建router文件夹>index.js
// 创建整个项目的路由器
// 引入vue-router
import VueRouter from 'vue-router'
// 引入组件
import Login from '../components/Login'
import Index from '../components/Index'
// 创建路由器并导出
export default new VueRouter({
routes:[
{
path:'/login',
component:Login
},
{
path:'/index',
component:Index
}
]
})
4、在main.js中引入路由器:
import router from './router/index'
new Vue({
el:'#app',
render:h=>{app},
router:router
})
5、跳转:
出口/视图:
注:
①标签属性active-calss:该路由被激活时的样式
②一般组件与路由组件的区别:开发中为了一般组件与路由组件,会将它们发到不同的文件夹之下进行管理,pages:路由组件
③不用的路由组件会被销毁,待使用时再挂载
components:一般组件
动态路由
5.2. 嵌套路由
注:子级路由在配置对应组件时,不需要以'/'开头;子级路由在进行路由跳转时,需要把父级带上。(
5.3. 路由传参
1、跳转路由并携带query参数:
①to的字符串写法:
在进行路由跳转时:
接收参数的组件使用$route(路由信息):this.$route.query.key1
②to的对象写法:
2、跳转路由并携带params参数:
在进行路由跳转时:
在路由配置时,在path属性中设置占位符(指明对应数据对应的对象):
{path:"/路由/:key1/:key2",component:组件}
接收参数的组件使用$route(路由信息):
this.\$route.params.key1
5.4. 命名路由
命名路由:在配置路由时增加name属性。
在路由跳转时就不用使用path属性编写多级路由,直接使用name属性即可。
注意:路由使用to的对象写法时,路由命名和params参数不可共存。
5.5. 路由的props配置
路由的props配置:在配置路由时添加props属性
第一种写法:props值为对象。该对象中的所有key-value都会以props的形式传给使用该路由的组件,然后在对应组件中接收props。(用的非常少,死数据)
第二种写法:值为布尔值。若为true,就会把改路由组件收到的所有params参数,以props的形式传给使用该路由的组件,然后在对应组件中接收props。
第三种写法:值为函数。依靠函数的返回值,返回值(对象)以props的形式传给使用该路由的组件。
5.6. router-link的replace属性
作用:控制路由跳转时操作浏览器历史记录模式。
浏览器的历史记录(栈)有两种写入方式:push和replace,push是追加历史记录,replace是替换当前记录,默认是push.
replace模式:取代栈顶的第一条数据(路由跳转时,当前路由会替换掉上一条路由,最终结果就是页面不能千金不能后退)
使用:
5.7. 编程式路由导航
有些时候我们无法使用
//e.g.
methods:{
goRouter(){
//this.$router.push({name:'rputeName',query:{}});
//this.$router.push({name:'rputeName',query:{}});
//this.$router.go(number);
this.back();
}
}
5.8. 缓存路由keep-alive
作用:让不展示的路由组件保持挂载,不被销毁。
//
5.9. 两(3)个新的生命钩子函数(activated,deactivated)
由路由缓存
作用:路由组件独有,用于捕获路由组件的激活/失活状态。
activated:路由组件被激活时触发
deactivated:路由组件失活时被触发
nextTick:在下一次DOM更新结束后执行其指定的回调函数。当改变数据后,要基于更新后的DOM进行某些操作,要在nextTick所指定的回调函数中执行。
5.10. 路由守卫(很重要!!!)
分类:全局守卫、独享守卫、组件内守卫(可搭配使用)
路由守卫:对路由进行权限控制,保护路由的安全。进入某个路由时,进行需求判断,条件为真才可进入该路由,否则跳回指定的其他路由。(防止在不登录的情况下在地址栏输入路径查看页面详情的情况发生)
1、全局前置路由守卫
使用:在路由器中给每个路由添加name属性,先使用变量接收路由器,再默认导出(不可简写),在导出之前进行路由守卫的编写beforeEach函数
beforeEach函数:初始化路由时被调用+每次路由切换之前被调用
to:目标路由(去哪里)
from:来自哪里
next:放行(接着往下走)
router.beforeEach((to,from,next)=>{
//前提条件,当前去的目标路由是否是我们需要进行守卫的路由,是:进入判断,否:放行
if(to.path==='/route1' || to.name==='/route1'...){
//是需要守卫的路由,那么就进行条件判断,满足就往下走,否则就修改目标路由
//例如,判断token是否有效,无效就跳到登录页面,有效就继续
if(!token){
next('/login')
}else{
next()
}
}else{
next()
}
})
export default router
!!!!!!如果需要守卫的路由很多的话,这种判断很繁琐,可以在路由配置时加路由源信息meta来控制是否需要守卫:
// 引入vue-router
import VueRouter from 'vue-router'
const router = new VueRputer({
routes:[
{
name:'**',
path:'/**',
meta:{isAuth:true},//需要守卫的路由为true
compontent:()=>import('/**')//按需引入路由组件,有效防止首屏加载慢或白屏问题
}
]
})
router.beforeEach((to,from,next)=>{
//前提条件:使用配置项进行判断是否路由守卫
if(to.meta.isAuth){
//是需要守卫的路由,那么就进行条件判断,满足就往下走,否则就修改目标路由
//例如,判断token是否有效,无效就跳到登录页面,有效就继续
if(!token){
next('/login')
}else{
next()
}
}else{
next()
}
})
export default router
2、全局后置路由守卫
后置路由守卫没有next参数,一般用于路由跳转后修改页面的标题title。
用法:在路由源信息meta中增加title属性,在路由跳转是进行修改:
// 引入vue-router
import VueRouter from 'vue-router'
const router = new VueRputer({
routes:[
{
name:'**',
path:'/**',
meta:{isAuth:true,title:'****'},
compontent:()=>import('/**')
}
]
})
router.beforeEach((to,fromt)=>{
if(to.meta.isAuth){
if(!token){
next('/login')
}else{
next()
}
}else{
next()
}
})
//使用后置路由守卫修改页面标题
router.afterEach((to,from)=>{
ducument.title = to.meta.title || '默认值'
})
export default router
3、独享路由守卫
独享路由守卫:只给某一个路由设置的守卫。只有前置没有后置!
{
name:'**',
path:'/**',
meta:{
isAuth:true,
title:'****',
beforeEnter:(to,from,next)=>{
if(to.meta.isAuth){
if(!token){
next('/login')
}else{
next()
}
}else{
next()
}
}
},
compontent:()=>import('/**')
}
4、组件内路由守卫
组件内路由守卫:直接在组件内编写beforeRouterEnter和afterRouterLeave(和钩子函数同级)
//beforeRouterEnter:通过路由规则,进入该组件时被调用
beforeRouterEnter(to,from,next){}
//afterRouterLeave:通过路由规则,离开该组件时被调用
afterRouterLeave(to,from,next){}
5.11. history模式和hash模式(仅从前端角度分析)
路由器的两种工作模式:history模式和hash模式
hash模式下,路径中的值称为哈希值,它不会随着http请求发给服务器。
hash模式(默认模式):地址栏带#号。兼容性好。
history模式:无#号。兼容性略差。
项目打包(npm run bind)前可将工作模式改为hash模式(哈希模式在部署发送网络请求时不会因地址栏参数产生404错误):更改工作模式:在路由配置项中 mode:'history或者hash'
若使用history模式,404报错的解决方法(使用node的中间件):
npm i connect-history-api-fallback
=>在server.js中引入:const history = require('connect-history-api-fallback')
=>使用(在使用静态资源之前):app.use(history)
扩展:使用node express搭建一个微型服务器
新建文件夹demo=>vscod打开=>安装express: 【
npm init
=>取名:test-server,一路回车=>npm i express
】=>创建server.js文件:=>服务器下一般有static(public)文件夹用来存放前端的文件(服务器要识别这些文件就需要借助中间件app.use来指定静态资源(express.static(__dirname+'static')))=>停掉重启即可在浏览器查看前端文件
将前端文件放入服务器静态资源文件夹下的过程就称之为部署。
//server.js
//引入express
const express = require('express')
//引入connect-history-api-fallback解决跨域
const history = require('connect-history-api-fallback')
app.use(history)
//创建服务对象
const app = express()
//借助中间件app.use来指定静态资源
express.static(__dirname+'static'))
//配置路由
app.get('/person',(request,response)=>{
//该路由给前端返回的信息
request.send({name:'jaja',age:18})
})
//监听端口
app.listen(50005,(err)=>{
if(!err) {
//服务器启动成功
}
})
5.12. Vue UI组件库
移动端常用:
vant:https://youzan.github.io/vant
Cube UI:https://didi.github.io/cube-ui
Mint UI:https://mint-ui.github.io
PC端常用:
Element UI:https://element.eleme.cn
IView UI:https://www.iviewui.com
使用(以Element UI为例):
打开官网=>组件(按着官网来就好了)
npm i element-ui=>在main.js中引入使用(import和use)=>引入样式(最好按需引入)=>使用:
按需引入:借助库babel-plugin-component:
安装:npm i babel-plugin-component -D(-D开发依赖)=>在babel.config.js下追加配置=>在main.js下引入需要的组件
六、Vue3
嗷嗷嗷,终于到vue3了!!!!!
Vue3快速上手
注:绝大部分截图来自尚硅谷张天禹老师教学视频