1、创建Vue脚手架
1.1、首先系统需要全局安装Vue脚手架
npm install -g @vue/cli
1.2、创建Vue脚手架工程
进入你想创建vue脚手架的目录,然后输入命令
vue create xxx项目名
需要注意的是工程名字不能大写,这里我们选择选择Vue2,敲下回车,那么vue将会为我们创建vue脚手架
显示如图所示说明创建成功
如图命令所示 我们进入myvue工程,执行命令
npm run serve
然后浏览器访问http://localhost:8080/
到这里 我们的vue脚手架工程就跑起来了,关闭为Ctrl+C
2、Vue脚手架的文件结构说明
├── node_modules
├── public
│ ├── favicon.ico: 页签图标
│ └── index.html: 主页面
├── src
│ ├── assets: 存放静态资源
│ │ └── logo.png
│ │── component: 存放组件
│ │ └── HelloWorld.vue
│ │── App.vue: 汇总所有组件
│ │── main.js: 入口文件
├── .gitignore: git版本管制忽略的配置
├── babel.config.js: babel的配置文件
├── package.json: 应用包配置文件
├── README.md: 应用描述文件
├── package-lock.json:包版本控制文件
3、修改默认配置
Vue-cli官网配置参考:https://cli.vuejs.org/zh/config/#publicpath
在工程根目录下创建文件vue.config.js
这里我们演示配置一下语法检查
3.1、配置前
会发现,默认语法检查是开启的,然后我们写了一个function没有被使用的话就会导致整个项目启动不了,所以在实际开发中,会带来很多障碍,所以我们将它关闭。
3.2、配置后
在vue.config.js中,加入以下代码
这时发现,默认配置已被修改,项目正常启动。
后序我们修改默认都可以结合官网的文档在该文件夹中配置
4、标签的 ref属性
因为在Vue里使用原生js拿去Dom元素不太好,所以就有了ref属性
4.1、ref属性的作用
1、被用来给元素或子组件注册引用信息(id的替代者)
2.应用在html标签上获取的是真是Dmo元素,应用在组件标签上的是组件实例对象(vc)
3.使用方法:
<h1 ref="xxx">......</h1> 或<组件ref="xxx"></组件>
获取:this.$refs.xxx
作用就相当于给一个表情加了个id=“xxx” 然后通过document.getElementById(“xxx”)的效果一样。
4.2、示范
编写一个School.vue组件,然后在App.vue中引入
我们访问网页 会发现,拿得到Dom元素,测试成功!
5、props配置
5.1、功能
让组件接收外部传递过来的数据,从而达到组件复用的目的
(1).传递数据
<Demo name="xxx"/>
(2).接收数据
第一种方式(只接收):
props:['name']
会发现以上会出现一个问题,如果我们需要传递18而显示19的话,那就需要做一下调整,因为默认传递过去的是一个字符串类型的数据,所以会造成字符串的拼接,所以我们得在传递的属性上面加 : 或者 v-bind ,他就会将表达式中的值正真的传递过去而不是以字符串的形式。
第二种方式(限制类型):
props{
name:String
}
会发现传递字符串的话就会报错,一样通过:或者v-bind解决
第三种方式(限制类型、限制必要性、指定默认值)
props:{
name:{
type:String, //类型
required:true, //是否必传
default:'老王'//默认值
}
}
备注:props是只读的,不能修改,Vue底层会检测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。
如图所示:
6、mixin混入
6.1、功能
(1)示范准备
可以看到School和Student组件中有相同的方法
我们可以将其抽取出来达到复用的效果。
(2)创建一个js文件将相同的代码抽取出来,然后在Student和School组件中分别导入。
(3) 测试
会发现 抽取出来的方法生效了!!!
6.2、补充
不光上面演示的代码能在写在混合中,Vue中的声明的东西也都可以写在混合中,比如mounted、create,也包括自己定义的一些属性等方法等…混合中的数据最终都会和组件中的数据作一个整合
(1)、示范
一、我们在混合中加入mounted代码块
二、我们在混合文件中加入一些属性。
这里我们重新暴露一个代码块,然后代码块中声明name数据,然后School和Student中导入
测试
会发现使用name值成功了。注意:从示例中我们可以看到,如果混合和组件中有相同的组件和方法,会以组件中的为准。但是如果是mounted钩子函数,那么都要。并且混合中的钩子函数中的内容会先被执行。
mounted钩子函数测试
两个组件都引入,会发现混合中的钩子函数内容会先被执行
6.3、全局混入
上面那些都属于局部混入,导入某个组件内仅供该组件使用。这里介绍全局混入,导入一次可在所有组件中使用混入文件。
6.4、总结
功能:可以吧多个组件的共同配置提取成一个混入对象
使用方式:
第一步定义混合,例如:
{
data(){....},
methods:{....}
}
第二部使用混入,例如:
(1).全局混入:Vue.minxin(xxx)
(2).局部混入:mixins:[xxx]
7、插件
7.1、功能
功能:用于增强Vue
本质:包含install方法的一个对象,install的第一个参数就是Vue,第二个以后的参数是插件使用者传递的数据。
定义插件:
对象.install=function(Vue,options){
//1.添加全局过滤器
Vue.filter(...)
//2.添加全局指令
Vue.directive(...)
//3.配置全局混入
Vue.minxin(...)
//4.添加实例方法
Vue.prototype.xxx=function(){
.....
}
Vue.prototype.xxx=(...)=>{
......
}
}
1、示范
先创建一个plugins.js文件,然后在文件中install方法中声明一些全局混入 或者方法等…
2、导入并且使用插件
在main.js 中导入并且在School组件中使用插件中定义的各种混入,方法,过滤器等…
3、测试
4、补充
在使用插件的时候 还可以传递参数
8、scoped样式
8.1、功能
作用:让样式在局部生效
写法:在style标签上加上scoped即可
<style scoped></style>
示范
在两个组件中都使用相同的样式
会发现样式会有冲突,所以我们在标签上加上 scoped
会发现,成功啦!!!
9、组件的自定义事件
9.1、props传递 方法
通过前面的知识我们可以知道,父组件在向子组件传递数据的时候可以在使用子组件时传递参数然后子组件中通过props属性接收参数,其实不光可以接受传递过来的属性,然后也可以接收传递过来的方法。然后子组件中调用方法,通过参数列表像父组件的方法中传递数据。
示范
需求:子组件中的数据传递到父组件中然后显示
(1)、准备一个student组件,然后父组件传递方法,子组件接收传递过来的方法
在子组件中调用父组件中的方法,则会回调父组件中传递的那个方法,参数则为子组件中传递的参数,那么父组件中就拿到子组件中传递过来的数据了。
(2)、测试
测试成功!!!
9.2、自定义事件(写法一)
上面的例子是通过props属性的方式实现的,我们还可以通过自定义事件的方式实现子组件 像父组件传递数据
示范
(1)、同样准备一个Student组件,然后在父组件中为子组件绑定事件和回调函数,然后在子组件触发父组件绑定的事件
触发事件用this.$emit('xxx',参数1,参数2...)
当然,参数想传递多少都是可以的。
(2)、测试
哈哈,成功啦!!!
9.3、自定义事件(写法二)
(1)、我们还可以通过ref的方式给指定的组件绑定事件
(2)、测试
成功啦!!!咋样,是不是很简单呢。
(3)、补充
既然能给组件绑定自定义事件,那么我们也可以解绑自定义事件,记住,给哪个组件绑定的事件就找那个组件触发去,同样,给哪个组件绑定的事件,就找哪个组件解绑
解绑指定的事件:this.$off('xxxxxx');
解绑多个事件:this.$off(['xxx','xxx']);
如果解绑所有事件,直接用: this.$off( );
解绑之后,那么这个事件就无法被触发了。
9.4、总结
组件的自定义事件
1、是一种组件间的通信方式,适用于子组件===>父组件
2、使用场景: A是父组件,B是子组件,B想给A传递数据,那么就要在A中给B绑定自定义事件和回调函数(回调函数在A中,参数则为B传递过来的)
3、绑定自定义事件:
- 第一种,在父组件中
<Demo @zidingyi="test"/>
或
<Demo v-on:zidingyi="test"/>
- 第二种,在父组件中
<Demo ref="demo"/>
......
mounted(){
this.$refs.demo.$on('zidingyi',this.test)
}
3.若想让事件只出发一次,可以使用**once**修饰符,或**$once**方法。
- 触发自定义事件:
在子组件中
this.$emit('zidingyi',参数1,参数二...)
- 解绑自定义事件
this.$off('zidingyi')
- 组件也可以绑定原生DOM事件,需要使用native修饰符。
比如:
<Demo @click.native="xxxx"/>
10、全局事件总线
10.1、功能
从上面props和自定义事件例子中可以看到,他们适用于父组件与子组件或者子组件与父组件中的数据传递进行通信,那么如何实现任意两个组件中的通讯呢?
我们可以使用全局事件总线,全局事件总线并不是一个新的技术或者API,只是编码的经验而已。
(1)、首先得先有一个存放数据的地方,并且这个存放的地方必须是所有组件都能看到的。
通过图中我们可以看到,若所有的vc要拿数据 x (this.xxx),如果x在vc中找不到,那么就会去找VueComponent的原型对象中找,但是每一个组件都会有一个新的VueComponent,所以数据是不共享的,所以不能存在这里,那么就继续往上找到Vue,Vue的原型对象是所有的组件vm或vc都能看到的,所以存在Vue的原型对象中再合适不过了。
(2)、在Vue的原型对象中存入一个组件,那么这个组件就能被其他所有的组件绑定事件或者触发事件,从而达到通讯的目的
在main.js文件中,构建一个组件并且存入Vue的原型对象中
(3)、准备两个组件Student和School组件,然后在Student给Vue原型对象中的组件绑定事件,然后School中触发事件
(4)、测试
会发现,Student组件中触发了School中给公用组件绑定的方法并且拿到了数据。到这里就实现了兄弟组件中的通讯了,不再局限于父穿子,子传父了。
(5)补充
除了上面那种在main.js 中先构建一个组件然后再存入Vue的原型对象中的写法外还有一种比较标准的写法
将之前原型对象的k为x都改为$bus (起这名是因为bus也总线的意思,哈哈),测试
10.2、总结
全局事件总进线(GlobalEventBus)
-
一种组件间通信的方式,适用于任意组件间的通信。
-
在main.js中开启全局事件总线:
new Vue({
......
beforeCreate(){
Vue.prototype.$bus=this //开启全局配置总线
}
})
- 使用事件总线:
3.1. 接收数据:A组件想要接收数据,则在A组件中给$bug绑定自定义事件,事件的回调留在A组件自身.
methods(){
demo(date){
}
}
......
mounted(){
this.$bus.$on('xxx',this.demo)
}
3.2. 提供数据
this.$bus.$emit('xxx',数据)
- 最好是在beforeDestory构子中,用$off去解绑当前组件所用到的事件。
11、消息的订阅与发布(pubsub.js)
11.1、介绍和使用步骤
除了上面全局事件总线的方式实现任意组件中的通讯,我们还可以借助 消息的订阅与发布(pubsub.js)实现任意的组件中的通讯。
使用步骤
- 安装pubsub:
npm i pubsub-js
- 在组件中引入:
import pubsub from 'pubsub-js'
- 接收数据:A组件中想要接收数据,则先在A组件中订阅消息,订阅的回调函数留在A组件自身
methods(){
demo(msgName,参数1,参数2){......}
},
......
mounted(){
this.pid=pubsub.subscribe('xxx',this.demo)//订阅消息
},
beforeDestroy(){
pubsub.unsubscribe(this.pid);
}
- 提供数据:
pubsub.publish('xxx',数据)
- 最好在beforeDestroy钩子中,用
pubsub.unsubscribe(pid)
取消订阅
11.2、示范
将之前给公用组件绑定自定义事件的方式替换成消息的订阅与发布
测试
测试成功啦!!!
12、$nextTick
12.1、功能
1、需求
如图所示,点击按钮,显示输入框并且输入框获取焦点
2、代码如图所示
3、测试
会发现根本就没有获取焦点
4、分析原因
在模版都没成功渲染的时候显然连Dom元素都没有获取到
5、解决
这里我们需要借助$nextTick解决
6、再次测试
会发现,成功显示输入框并且输入框也获取了焦点
12.2、总结
- 语法:
this.$nextTick(回调函数)
- 作用:在下一次DOM更新结束后执行指定的回调。
- 什么时候用:当改变数据后,要基于更新后的DOM进行某些操作时,要在nextTick所指定的回调函数中执行
13、animate.css
13.1、功能
animate.css包含了很多动画效果,这里我们试一下 显示/隐藏 的动画效果。有了它,我们不再需要自己手写C3动画样式了。非常nice
官网:点击进入首页
示范:
我们准备一个Test组件
1、安装animate.css :npm install animate.css
2、在组件中引入import 'animate.css'
3、设置显示和隐藏时的动画效果
我们在官网找到想要的样式
编写代码,appear为true时表示进入网页时组件第一次渲染就开始显示配置的效果
4、测试
很方便对不对,nice
14、反向代理
在解决ajax跨域问题时,后端人员经常会配置CORS解决跨域,但是作为前端,我们也可以通过自己的反向代理的方式解决跨域,这样就不用麻烦后端开发人员。
我们先准备两个接口,这里有使用node-js写的两个服务器。先下载运行起来
链接:https://pan.baidu.com/s/1Tbezmmg7vj_NpqxysYgCjg
提取码:1024
解压之后我们通过node运行
测试一下接口是否正常返回数据:
接下来我们写一个组件通过ajax的方式去请求接口,这里我们使用axios发起请求,当然得先安装axios:npm i axios
会发现,产生了跨域问题,接下来我们用以下两种方式解决跨域
14.1、方式一
官网配置说明:点击直达
在vue.config.js中加入配置
module.exports = {
devServer: {
proxy: 'http://localhost:4000'
}
}
重启脚手架项目,这样vue-cli就为你开启了一个8080的代理服务器去代理5000的服务器
重新发起请求
注意,如果我们8080的服务器上本身就有和5000相同的资源,代理服务器就不会把我们的请求转发给5000
14.2、方式二
会发现方式一存在两个问题,一是不能配置多个代理,二是不能灵活的控制请求是否转发。
编写vue.config.js具体规则
module.exports = {
devServer: {
proxy: {
'/api1': {// 匹配所有以 '/api1'开头的请求路径
target: 'http://localhost:5000',// 代理目标的基础路径
changeOrigin: true,
pathRewrite: {'^/api1': ''}
},
'/api2': {// 匹配所有以 '/api2'开头的请求路径
target: 'http://localhost:5001',// 代理目标的基础路径
changeOrigin: true,
pathRewrite: {'^/api2': ''}
}
}
}
}
/*
changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080
changeOrigin默认值为true
*/
配置完我们需要重启服务器,我们将请求前缀加上/api1 或/api2,测试。
说明:
1.优点:可以配置多个代理,且可以灵活控制请求是否走代理
2.缺点:配置略微繁琐,请求资源时必须加前缀。
15、插槽
15.1、插槽的介绍和使用方式
1、作用:让父组件可以向子组件指定的位置插入html结构,也是一种组件间通信的方式,适用于父组件===>子组件。
2、分类:默认插槽、具名插槽、作用域插槽
3、使用方式:
- 默认插槽:
父组件中:
<xxx组件>
<div>html结构1</div>
</xxx组件>
子组件中:
<template>
<div>
<slot>插槽默认内容...</slot>
</div>
</template>
- 具名插槽
父组件中:
<xxx组件>
<template slot="center">
<div>html结构1</div>
</templat>
<template v-slot:footer>
<div>html结构2</div>
</templat>
<xxx组件>
子组件中:
<template>
<div>
<!--定义插槽-->
<slot name="center">插槽默认内容...</slot>
<slot name="footer">插槽默认内容</slot>
</div>
</template>
- 作用于插槽
1、理解:数据在组件自身,但数据生成的结构需要组件的使用者来决定,意思就是说,组件的使用者可以拿到组件中提前定义好的数据 然后在使用时根据自己的需求进行渲染。
2、具体编码
父组件中:
<xxx组件>
<!--或者scope换成slot-scope也行-->
<template scope="scopeData">
<!--生成的是ul列表>
<ul>
<li v-for="g in scopeData.games" :key="g" >{{g}}</li>
</ul>
</template>
</xxx组件>
子组件中:
<template>
<div>
<slot :games="games"></slot>
</div>
</template>
<script>
export default{
name:'Category',
//数据在组件自身
data(){
return{
games:['红色警戒','穿越火线','劲舞团']
}
}
}
</script>
15.2、默认插槽
首先我们准备一Category1组件,在组件中定义一个插槽,然后使用这个组件时动态是插入html结构内容
测试成功、
15.3、具名插槽
默认插槽只能定义一个插槽,我们可以使用具名插槽定义多个插槽。我们准备一个Category2组件,在其中声明两个插槽
测试成功
15.4、作用域插槽
准备一个组件Category3,并定义插槽携带数据
测试成功
16、Vuex
16.1、vuex是什么?
-
概念:专门在Vue中实现集中式状态(数据)管理的一个Vue插件,在Vue应用中多个组件共享状态进行集中式管理(读/写),也是一种组件间通信方式,且适用于任意组件中的通信。(说白了就像后端中的redis可以用来多个应用中做数据共享)
-
Github地址:https://github.com/vuejs/vuex
16.2、什么时候使用Vuex
- 多个组件依赖于同一状态
- 多个组件的行为需要变更同一状态
16.3、Vuex原理图
现在看不懂没关系,我们逐个分析…
16.4、搭建Vuex环境
注意:在2022年的2月7日,vue3成为了默认版本,如果我们现在去执行npm i vue ,安装的直接就是vue3了,并且在vue3成为默认版本后。vuex更新到了4版本,所以我们如果执行npm i vuex,安装的是vuex4,而vue3版本只能在vue3版本中使用。
所以简单来说:
vue2中,要用vuex的3版本
vue3中,要用vuex的4版本
1、安装vuex并使用vuex插件
npm i vuex@3
2、为了让所有的vm和vc都拥有$store,所以我们需要配置store
在src文件夹下创建store文件夹和index.js文件
测试:
调整写法
index.js文件内容
//该文件用于创建VUex中最为核心的store
import Vue from 'vue'
//引入VUex
import Vuex from 'vuex'
Vue.use(Vuex)
//准备actions-用于响应组件中的动作
const actions={
}
//准备mutations-用于操作数据(state)
const mutations={
}
//准备state-用于存储数据
const state={
}
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state,
})
这回,就没有报错了!!!
测试vm和vc中是否包含$store,我们直接在mounted钩子中打印this
成功啦,之后$store中那些强大的API我们就都可以在任意vm和vc中使用了。
16.5、求和案例
现在的需求:
16.5.1、纯Vue版本
16.5.2、Vuex版本
测试
16.6、Store中的getters配置项
1、概念:当state中的数据需要经过加工后再使用时,可以使用getters加工。他就和vue中的计算属性是一样的。
2、在./store/index.js中追加getters配置
......
const getters={
bigSum(state){
return state.sum*10
}
}
//创建并暴露store
export default new Vuex.Store({
......
getters
})
3、组件中读取数据:$store.getters.bigSum
4、示范
5、测试
完美。
16.7、mapState与mapGetters
16.7.1、mapState
1、会发现如过store中的state中有多个属性数据需要读取,就比较繁琐
2、我们可以通过计算属性来进行简化
16.7.2、mapGetters
mapGetters和mapState的用法一样,只不过它拿的是store中的getters中的数据
16.7.3、总结
1.mapState方法:用于帮助我们映射state中的数据为计算属性
computed:{
//借助mapState生产计算属性:sum、address、subject
...mapState({sum:'sum',address:'address',subject:'subject'})
//借助mapState生成计算属性:sum、address、subject
...mapState(['sum','address','subject'])
}
2.mapGetters方法:用于帮助我们映射getters中的数据为计算属性
computed:{
//借助mapGetters生成计算属性:bigSum(对象写法)
...mapGetters({bigSum:'bigSum'}),
//借助mapGetters生成计算属性:bigsum (数组写法)
...mapGetters(['bigSum'])
}
16.8、mapActions和mapMutations
16.8.1、mapActions
16.8.2、mapMutations
16.8.3、总结
- mapActions方法:帮助我们生成与actions对话的方法,即:包含$store.dispath(xxx)的函数
methods:{
//借助mapActions生成与actins的对话的方式(对象写法)
...mapActions({increment:'increment',incrementWait:'incrementWait'})
//数组形式的写法
...mapActions(['increment','incrementWait'])
}
- mapMutations方法:用于帮助我们生成与mutations对话的方法,即: 包含$store.commit(xxx)的函数
methods:{
//借助mapMutation生成与**mutations**对话的方法(对象形式)
...mapMutations({INCREMENT:"INCREMENT"})
//数组写法
...mapMutations(['INCREMENT'])
}
16.9、Vuex的模块化编码
会发现,结合上面的技术,我们已经能完成数据的共享以及我们想要的功能。但随之也带来了一些问题,那就是如果业务量很大,模块很多,那么Store中的actions或者mutations以及state就会写得很长,不利于
所以我们可以使用模块化+命名空间将Vuex的模块进行分类,
就是说
订单模块调用订单模块的store,
支付模块调用支付模块的store
16.9.1、模块化+命名空间
1.目的:让代码更好维护,让多种数据分类更加明确
2.修改store.js
const module1={
namespaced:true,
actions:{ ... },
mutations:{ ... },
state:{ ... },
getters:{ ... }
}
const module2={
namespaced:true,
actions:{ ... },
mutations:{ ... },
state:{ ... },
getters:{ ... }
}
const store = new Vuex.Store({
modules:{
//module:module
// es6 简写
module1,
module2
}
})
3、开启命名空间后,组件中读取state数据:
//方式一:直接读取
this.$store.state.xxxxx模块.sum
//方式二:借助mapState读取
...mapState('xxxxx模块',['sum','subject'])
4、开启命名空间后,组件中读取getters数据:
//方式一:自己直接读取 不能直接写 getters.xxx模块.BigSum
this.$store.getters['xxx模块/bigSum']
//方式二:借助mapGetters读取:
...mapGetters('xxx模块',['bigSum'])
5、开启命名空间后,组件中调用dispath
//方式一:自己直接dispath
this.$store.dispath('xxx模块/increment',this.xxx)
//方式二:借助mapActions 或者对象写法('xxx模块',{increment:'increment'})
...mapActions('xxx模块',['increment'])
6、开启命名空间后,组件中调用commit
//方式一:自己直接commit
this.$store.commit('xxx模块/INCREMENT',this.xxx)
//方式二:通过mapMutations
...mapMutations('xxx模块',['INCREMENT'])
16.9.2、测试
通过$store的方式,我们准备一个Count组件和Count模块
测试完美!!!
通过map映射的方式,准备另外一个Studentr组件和studentOptions模块
测试完美!!!
补充、
当然也可以将各个模块抽取出来,然后在index文件中导入,这样模块的划分就更加清晰
17、路由
17.1、路由的简介
说白了,路由就是一组组Key–Value的对应关系。
(1)、理解:一个路由(route)就是一组映射关系(key-value),多个路由需要路由器(router)进行管理
(2)、前端路由:key是路径,value是组件
17.2、路由的基本使用
17.2.1、安装vue-router
注意,在2022年2月7日以后,vue-router的默认版本为4版本,并且:Vue-router3才能再Vue2中使用
所以我们得安装Vue-router3
npm i vue-router@3
17.2.1、使用vue-router
1、首先创建一个叫router的文件夹,并创建index.js,我们创建并暴露一个路由器VueRouter
2、在main.js中引入VueRouter并use,然后配置router
3、准备两个组件,随便写点内容
4、在路由器中配置路由数组routes 它里面包含很多路由。
5、然后我们在App.vue中可以开始使用路由了
6、测试
17.3、几个注意点
1、用单独的文件夹保存路由跳转的组件
2、通过切换后,"隐藏"了的路由组件默认是被自动销毁掉的,需要的时候会自动从新挂载。
3、每个组件都有自己的$route
属性,里面存储着关于自己的路由信息。
4、整个应用只有一个路由器router,可以通过组件的$router
属性获取到。
17.4、嵌套路由
就是路由组件里继续路由跳转到路由组件
1、首先,我们添加一些样式,并说明一下需求
我们点击“学生管理”,然后会出现旁边父路由的信息,然后点击父路由组件中的 “学生信息” 或者 “学生地址”
2、我们再准备两个组件News和Address,随便加点内容,这两个是子组件中要显示的内容
3、我们编写路由规则
4、测试,完美!!!
总结:
多级路由:
1.配置路由规则,使用children配置项:
routes:[
{
path:'/class',
component:Class
},
{
path:'/student',
component:Student,
children:[
{
path:'news',
component:News
},
{
path:'address', //此处千万不要写 /address
component:Message
}
]
}
]
17.5、路由的query参数(路由跳转时传递参数)
1.、现在新的需求,要求点击某条消息,然后显示消息的id和消息的详情信息
2、可以看到 学生消息路由里面还包含路由,三级路由了
并且点击的时候还还需要将参数动态的传递给第三级的路由组件。
首先我们创建一个Details组件并配置好路由规则
3、路由跳转时携带参数
4、测试成功啦!!!
17.6、命名路由(简化跳转)
我们会发现,从上述的例子中可以看到,如果路由嵌套过多,那么跳转的时候 路径就会写得很长,那么我们可以给该路由定义一个名字来简化跳转
17.7、路由的params参数
打印this 我们可以看到不光query可以携带参数,我们也可以通过params携带参数
在路由的path中添加占位符,通过params携带参数,然后路由组件中就可以从params中携带拿到参数
测试 接收参数
17.8、路由的props配置
路由的props配置的三种写法
{
name:'ces',
path:'detail/:id/:detail'
component:Detail,
//第一种写法:props值为对象,该对象所有的的key-value最终通过通过props传给Detail组件
// props:{a:900}
//第二种写法:props值为布尔值,布尔值为true,则把路由收到所有params参数通过props传递给Detail
//props:true
//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传递给Detail组件
props($route){
return {
id:$route.query.id,
detail:$route.query.detail
}
}
}
第一种写法只能传递固定的数据,不灵活,所以就不演示了。
第二种写法:注意这种写法只能传递params中的key-value…
第三种写法
17.9、router-link的replace属性
1、作用:控制路由跳转时操作浏览器历史记录的模式
2、浏览器的历史记录有两种写入方式:分别是push和replace,push是追加历史记录,replace是替换当前记录。路由跳转时候默认为push
3.如何开启replace模式:<router-link replace .......>News</router-link>
首先,我们点击
会发现 会从消息二回到消息一
测试 我们在Student的组件和他的子路由 News的路由跳转中加入replace属性
再按照刚刚的点击顺序
说白了 replace 加入之后 该路由 跳转的记录不会在浏览器留下痕迹
17.10、编程式路由导航 (通过$router跳转)
通过上面的例子,我们不仅可以通过<router-link>
标签进行跳转,我们还可以通过$router
进行跳转,我们之前就说过,每个组件都有自己的$route
而所有的组件共用一个$router
我们看一下现在的需求:
我们通过点击按钮然后调用$router.push
跳转到指定组件
通过$replace
进行跳转
测试成功
接下来编写前进和后退的代码以及go的代码
就和点击浏览器前进和后退的箭头一样。之后我们就可以通过$router
的这些API实现各种组件 类似于页面条页面的路由跳转啦!!!
17.11、缓存路由组件
1.作用:让不展示的路由组件保持挂载,不被销毁。
2.具体编码:
//指定一个组件不被销毁
<keep-alive include="具体不被销毁的组件名">
<router-view></router-view>
</keep-alive>
//指定多个缓存不被销毁
<keep-alive :include="['xxx','xxx']">
<router-view></router-view>
</keep-alive>
示范:
我们希望从新回到该路由组件的时候,输入的内容还在
所以我们可以使用缓存路由组件keep-alive
,我们在显示的视图使用router-view
时顺便使用keep-alive
即可测试
17.12、两个新的生命周期钩子
- 作用:路由组件所独有的两个钩子
- 具体名字:
-
activated
路由组件被激活时触发 -
deactivated
路由组件失活时触发
-
示范:
我们在Address组件中添加上这两个钩子函数
17.13、 路由守卫(权限控制)
17.13.1、全局前置守卫
需求:
所以 我们可以在可以使用路由的前置守卫控制某个路由是否放行
1、首先在LocalStorage中存入key
2、在路由器中配置前置守卫
3、当role为vip时
4、我们改一下role的值、测试成功
补充
从上面的例子中我们可以看到,如果每次都拿到path或者name去判断的话太长了,也不方便,。我们可以通过在meta属性中加上数据,表面这个路由是否需要被判断。
17.13.2、全局后置守卫
很少使用,一般用来修改网页的title
17.13.3、独享守卫
上面的都是对所有路由都有效的,独享守卫就是对某一个路由有效,
并且 独享守卫只有前置,没有后置。
17.13.4、组件内守卫
说白了就是写在组件内的路由守卫,我们直接写在Class组件中。
测试
17.14、路由器的两种工作模式
- 对于一个url来说,什么是hash值?—#以及后面的内容就是hash值,
- hash值不会包含在HTTP请求中,即:hash值不会带给服务器。
- hash模式:
- 地址中永远带着#号,不美观。
- 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
- 兼容性较好。
- history模式:
- 地址干净,美观。
- 兼容性和hash模式相比略差。
- 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。
设置:
默认是hash,如果想换成history则可设置
hash模式下的地址栏
history模式下的地址栏
记住:history模式部署上线前记得对服务器进行相关配置解决history刷新地址栏报404的问题。
18、Element-UI 组件库
18.1、Element-UI基本使用
官网:
https://element.eleme.cn/#/zh-CN/component/installation
根据官网进行安装
npm i element-ui
安装完之后在main.js 中添加以下代码,则可在所有的组件中使用element ui了
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
我们在App.vue中直接使用一下Element-UI提供的组件库
18.2、Element-UI按需引入
1、安装babel插件
npm install babel-plugin-component -D
2、配置.babelrc文件,注意:vue-cli中已经不存在.babelrc文件了,babel的配置在 babel.config.js
文件中
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset',
["@babel/preset-env", { "modules": false }]
],
plugins: [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
注意,如果按照官网的话可能会出现,这个错误(因为官网的文档可能不是最新的)
我们改个地方就可以了。
3、我们根据官网,按需引入即可
比如我只使用button和row组件
import { Button, Row } from 'element-ui';
Vue.component(Button.name, Button);
Vue.component(Row .name, Row);
测试
19、后记
生活朗朗,万物可爱,人间值得,未来可期。恭喜你,完结撒花!!!