Vue: 用于构建用户界面的渐进式框架。包含声明式渲染、组件系统、客户端路由、大规模状态管理、构建工具。
Vue官网地址:vue2 介绍 — Vue.js
Vue3 介绍 — Vue.jsVue.js - 渐进式 JavaScript 框架 | Vue.js
1. 创建一个Vue实例
设置容器----引入Vue.js----创建Vue实例-----添加配置
<!-- 设置容器 -->
<div id="app">
{{ msg }} <!-- 插值表达式 渲染页面页面-->
</div>
<script src="vue.js"></script>
<script>
//创建Vue实例
const app = new Vue({
el: '#app', //挂载容器
//声明数据
data: {
msg: 'Hello World!'
}
})
</script>
2. 插值表达式
语法格式 {{ 表达式 }}。可以动态响应式渲染页面。
表达式使用js语法进行解析,不能包含条件或逻辑判断语句如:if,表达式中引用的变量必须在Vue实例data中声明。
3. Vue指令介绍
1). v-html:
解析Html标签
<div v-html="html"></div>
2). v-show:
控制元素的显隐性,其实现原理是通过控制css的display属性控制元素是否显示。适用于显隐性变化频繁的场景。
3). v-if:
条件渲染,其原理是通过表达式值,判断是否添加或移除dom元素。
<div v-show="Math.random() > 0.5">
Now you see me show
</div>
<div v-if="Math.random() > 0.5">
Now you see me if
</div>
<div v-else>
Now you don't
</div>
v-else: 配合v-if使用,不需要表达式
v-else-if: 配合v-if使用
4). v-on:
绑定事件,通过方法或内联语句绑定,可以缩写为@
-
修饰符:
.stop
- 调用event.stopPropagation(),阻止冒泡
。eg:存在包含行为,只执行最上层行为。.prevent
- 调用event.preventDefault(),阻止默认行为
。eg:链接不跳转.capture
- 添加事件侦听器时使用 capture 模式。.self
- 只当事件是从侦听器绑定的元素本身触发时才触发回调。.{keyCode | keyAlias}
- 只当事件是从特定键触发时才触发回调,@keyup.enter监听回车按键。.native
- 监听组件根元素的原生事件。.once
- (2.1.4) 只触发一次回调。.left
- (2.2.0) 只当点击鼠标左键时触发。.right
- (2.2.0) 只当点击鼠标右键时触发。.middle
- (2.2.0) 只当点击鼠标中键时触发。.passive
- (2.3.0) 以{ passive: true }
模式添加侦听器
<!-- 只点击一次 -->
<button v-on:click.once="warn('Form cannot be submitted yet.', $event)">
Submit
</button>
5). v-bind:
绑定数据到属性或组件,可以缩写为:
可以动态控制class,用于标签高亮切换等
<div :class="{ css属性名:boolean, css属性名2:boolean }"></div>
<div :class="[ css属性名, css属性名2 ]"></div>
也可以与style合用,数据驱动设置样式动态变化,例如:进度条,行内样式增强
<div :style="{ css属性名:属性值, css属性名2:属性值 }"></div>
6). v-for:
基于数据循环,可以多次渲染整个元素。当和 v-if
一起使用时,v-for
的优先级比 v-if
更高。:key属性,列表元素的唯一标识,将数据和元素作为一个整体一起修改。key的值只能是字符串或数字,唯一
<div v-for="(item, index) in items" :key="item.id"></div>
<div v-for="(val, key) in object"></div>
<div v-for="(val, name, index) in object"></div>
7). v-model:
本质是语法糖。实现数据和视图的双向绑定,用于表单,可以获取或设置form元素的内容。
-
修饰符:
- .lazy - 取代
input
监听change
事件 - .number - 输入字符串转为有效的数字
- .trim - 输入首尾空格过滤
- .lazy - 取代
利用语法糖原理,在自定义组件中使用v-model,代替原有值和默认事件。当子组件接收父组件值,使用value时,可以不适用model属性,否则必须加model声明
自定义组件中的值传递,也可以使用.sync实现
父组件
<SonA :pData.sync="pData"></SonA>
子组件
<template>
<div>
我是子组件A ,测试v-model语法糖
<input :value="pData" @input="changeFatherValue"/>
</div>
</template>
<script>
export default {
//props:['pData']
props: {
pData:{
type: String
}
},
methods:{
changeFatherValue(e){
this.$emit('update:pData', e.target.value);//必须使用 update
}
}
}
</script>
8)自定义指令 directive/directives
封装一些对dom元素的操作。自定义指令中的钩子有bind、inserted、update、unbind、componentUpdated
<span v-color='colorD'>测试全局指令</span>
//全局自定义指令,focus是自定义的指令名,binding.value可以获取自定义指令的值
Vue.directive('color', {
//组件加载时调用
inserted(el, binding){
el.style.color=binding.value
},
//指令绑定数据时调用
update(el, binding){
el.style.color=binding.value;
},
})
//局部自定义指令
directives: {
color: {
//组件加载时调用
inserted(el, binding) {
el.style.color = binding.value
},
//指令绑定数据时调用
update(el, binding) {
el.style.color = binding.value;
},
}
}
4. 选项/数据
1). computed
计算属性,基于现有数据,自动计算其他属性,会自动变化,同时可以设置get\set方法,使用的时候计算属性中的方法名作为普通属性使用。
<div id="app">
<div>总数为:{{ total }}</div>
</div>
<script src="vue.js"></script>
<script>
//创建Vue实例
const app = new Vue({
el: '#app', //挂载容器
//声明数据
data: {
alist: [{"id": 1,"num": 2},{"id": 2,"num": 5},{"id": 3,"num": 8}],
},
computed: {
total: function(){
return this.alist.reduce((sum, item)=> sum + item.num, 0);
},
// 读取和设置
aPlus: {
get: function () {
return this.a + 1
},
set: function (v) {
this.a = v - 1
}
}
},
})
</script>
计算属性相较于method,具有缓存特性,对于同一属性,多副本使用的情况,计算属性只执行一次,可以有效提高性能。
2). watch
监听数据变化,数据变化后执行函数或方法。
<div id="app">
测试watch监听<textarea v-model="obj.info"></textarea>
<button @click="addObj">添加对象属性</button>
</div>
<script>
//创建Vue实例
const app = new Vue({
el: '#app', //挂载容器
//声明数据
data: {
obj: {
info: ""
},
},
methods: {
addObj: function () {
this.obj.newP= '333';//无法监听到新增属性
this.$set(this.obj,"newP",5555);//可以监听到新增属性
}
},
watch: {
//防抖设置
'obj.info'(newValue, oldValue) {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
console.info(newValue + '<----' + oldValue);
}, 1000);
},
obj: {
deep: true, //监听复杂对象,深度
immediate: true, //在监听开始执行一次
handler: function (newValue, oldValue) { //oldValue与newValue值相同
clearTimeout(this.timer);
this.timer = setTimeout(() => {
console.info(JSON.stringify(newValue) +'----'+ JSON.stringify(oldValue));
}, 1000);
}
}
}
})
</script>
watch监听复杂对象,对于新加入的属性,
如果使用this.objectName.propertyName=value方式无法进行监听;原因是vue在初始化的时候,会对复杂对象中的每一个属性设置get\set监听,所以新增属性无法检测到
如果使用this.$set(this.objectName,"propertyName",value)方式可以进行监听;
watch监听复杂对象时handler方法中,无法获取的变化前的值。
3) data
Vue 实例的数据对象。Vue 会递归地把 data 的 property 转换为 getter/setter,从而让 data 的 property 能够响应数据变化。对象必须是纯粹的对象 (含有零个或多个的 key/value 对):浏览器 API 创建的原生对象,原型上的 property 会被忽略。大概来说,data 应该只能是数据 - 不推荐观察拥有状态行为的对象。
data在组件中必须是一个函数,通过return返回数据,保证每一个组件实例,维护独立的一份数据对象。
<script>
//创建Vue实例
const app = new Vue({
el: '#app', //挂载容器
//声明数据
data: {
obj: {
info: ""
},
},
//组件中写法
data() {
retutn {
obj: {
info: ""
},
}
},
})
</script>
5. Vue的生命周期
Vue实例从创建到销毁的过程,分为四个阶段:创建(生成响应式数据data)、挂载(渲染模板)、更新(更新视图,修改数据)、销毁(销毁实例)
钩子函数:在Vue的生命周期周,提供给开发人员,运行业务代码的方法。包含:
- beforeCreate(实例初始化之后,进行数据侦听和事件/侦听器的配置之前。响应式数据准备好之前,无法获取到data数据);
- created(响应式数据准备好之前,可以获取到data数据。在这一步中,实例已完成对选项的处理,意味着以下内容已被配置完毕:数据侦听、计算属性、方法、事件/侦听器的回调函数);
- beforeMount(模板渲染之前,无法获取到dom);
- mounted(模板渲染之后,可以获取到dom);
mounted
不会保证所有的子组件也都被挂载完成。如果你希望等到整个视图都渲染完毕再执行某些操作,可以在 mounted
内部使用 vm.$nextTick:
mounted: function () {
this.$nextTick(function () {
// 仅在整个视图都被渲染之后才会运行的代码
})
}
- beforeUpdate(数据修改后,dom渲染前,获取到修改后的数据,修改前的dom);
- updated(dom渲染后,获取到修改后的数据,修改后的dom);
- beforeDestroy(卸载前,切除vue以外的资源调用);
- destroyed(卸载后);app.$destroy()
6. Vue脚手架安装与使用
1). 安装vue-cli,执行yarn global add @vue/cli 或者 npm i @vue/cli
PS C:\Users\******> npm i @vue/cli -g
npm WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead.
npm WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead.
npm WARN deprecated source-map-url@0.4.1: See https://github.com/lydell/source-map-url#deprecated
......
npm WARN deprecated subscriptions-transport-ws@0.11.0: The `subscriptions-transport-ws` package is no longer maintained. We recommend you use `graphql-ws` instead. For help migrating Apollo software to `graphql-ws`, see https://www.apollographql.com/docs/apollo-server/data/subscriptions/#switching-from-subscriptions-transport-ws For general help using `graphql-ws`, see https://github.com/enisdenjo/graphql-ws/blob/master/README.md
npm WARN deprecated shortid@2.2.16: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.
added 855 packages in 3m
PS C:\Users\*******>
2). 查看vue版本 vue --version
3). 创建项目 vue create 项目名(项目名不能使用中文)
D:\workspace\learn>vue create vue-demo
Vue CLI v5.0.8
? Please pick a preset: Default ([Vue 2] babel, eslint)
Vue CLI v5.0.8
✨ Creating project in D:\workspace\learn\vue-demo.
🗃 Initializing git repository...
⚙️ Installing CLI plugins. This might take a while...
npm WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead.
added 866 packages in 3m
🚀 Invoking generators...
📦 Installing additional dependencies...
npm WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead.
added 94 packages in 2m
⚓ Running completion hooks...
📄 Generating README.md...
🎉 Successfully created project vue-demo.
👉 Get started with the following commands:
$ cd vue-demo
$ npm run serve
WARN Skipped git commit due to missing username and email in git config, or failed to sign commit.
You will need to perform the initial commit yourself.
D:\workspace\learn>
4). 启动项目 yarn serve或npm run servr(package.json中的名称)
D:\workspace\learn\vue-demo>npm run serve
npm WARN config global `--global`, `--local` are deprecated. Use `--location=global` instead.
> vue-demo@0.1.0 serve
> vue-cli-service serve
INFO Starting development server...
DONE Compiled successfully in 3746ms 15:38:18
App running at:
- Local: http://localhost:8080/
- Network: http://***.***.***.***:8080/
Note that the development build is not optimized.
To create a production build, run npm run build.
7. Vue组件
1). 组件组成成分
组件由三部分组成,分别是结构(template)、样式(style)、行为(script)
注意:
1. 结构只能有一个,<template>里只能有最外层的<div>只能有一个
2.样式默认是全局的,局部样式需要增加scoped,只作用于当前组件。
例如:<style scoped></style>
scoped原理是:给当前组件模板的所有元素增加一个自定义属性,以data-v-hash值作为div样式选择器,可以使用data-v-hash区分你不同的组件。
2). 组件间传值
1. 父组件传值到子组件props
父组件调用子组件时,将要传递的数据注册到子组件的标签里,子组件使用props接收父组件转过来的值。props可以对接收的值设置数据类型、是否非空、默认值、自定义校验方法。
props复杂校验
<script>
export default {
//props:['pData']
props: {
pData: String,
jsonData: {
type: Object,//数据类型
default: ()=> {},//默认值
required: true,//非空
validator(val){ //自定义校验方法
if(val.info==1){
return false;
}else{
return true;
}
}
}
}
}
</script>
tips:props使用时遵循单项数据流原则,在子组件中不建议直接修改。
2. 子组件传值到父组件
子组件传值到父组件,子组件使用vm.$emit注册事件,父组件监听事件,调用方法获取子组件返回的数据并处理。
<!-- 父组件 -->
<template>
<div id="app">
<SonC @eventName1="receiveSonData"></SonC>
</div>
</template>
<script>
import SonC from './components/SonC.vue'
export default {
name: 'App',
components: {
SonC
},
methods:{
receiveSonData(val, val2){
alert(val + "----" + val2);
}
}
}
</script>
<!-- 子组件 -->
<template>
<div>
<button @click="trsData">调用父组件</button>
</div>
</template>
<script>
export default {
data(){
return {
sonData:22223,
sonData2:33333
}
},
methods:{
trsData(){
this.$emit("eventName1", this.sonData, this.sonData2);//事件名,参数1,参数2..
}
}
}
</script>
参数值可以输多个,监听事件名与注册事件名保持一致
3. 非父子组件间传值 --事件总线(event bus)
适用于简易消息处理。类似于观察者模式。
实现步骤:
1.创建Bus总线实例,Bus实例区别与原有的项目实例,独立存在;
2.在接受消息的组件中引入Bus,在vue实例created中使用$on接收消息;
3.在发送消息组件中使用$emit触发事件。
<!-- 主页面 -->
<template>
<div id="app">
<ComA></ComA>
<ComB></ComB>
<SendMsgC></SendMsgC>
</div>
</template>
<script>
import ComA from './components/ComA.vue';
import ComB from './components/ComB.vue';
import SendMsgC from './components/SendMsgC.vue';
export default {
name: 'App',
components: {
SendMsgC,
ComA,
ComB
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
<!-- 发送消息组件 -->
<template>
<div>
<button @click="sendMsgs">发送消息</button>
</div>
</template>
<script>
import eventBus from '@/utils/eventBus.js';
export default {
methods:{
//发送消息
sendMsgs(){
eventBus.$emit("event1",2222, 444);
console.info("wwwwww");
}
}
}
</script>
<!-- 接受消息组件A -->
<template>
<div>
接收A {{ msg }}
</div>
</template>
<script>
import eventBus from '@/utils/eventBus.js';
export default {
data(){
return {
msg:""
}
},
created() {
eventBus.$on('event1', (msg1,msg2)=>{
this.msg = (msg1+"===="+msg2);
})
}
}
</script>
<!-- 接受消息组件B -->
<template>
<div>
接收B {{ msg }}
</div>
</template>
<script>
import eventBus from '@/utils/eventBus.js';
export default {
data(){
return {
msg:""
}
},
created(){
eventBus.$on('event1', (msg1,msg2)=>{
this.showMsg(msg1,msg2)
});
},
methods:{
showMsg(msg1,msg2){
console.info("ssss");
this.msg = (msg1+"===="+msg2);
}
}
}
</script>
注意:发送消息和接收消息要在同一个事件总线的vue实例里,不要使用this。
4. 非父子组件间传值(跨层级 provide & inject)
跨层级共享数据。顶层组件使用provide函数设置共享数据,子孙组件使用inject接收数据。
<!-- 顶层组件 -->
<template>
<div id="app">
<button @click="changeTopData">修改顶层组件数据</button>
</div>
</template>
<script>
import ComA from './components/ComA.vue';
export default {
name: 'App',
components: {
ComA
},
provide(){
return {
pData: this.pData,
jsonData: this.jsonData
}
},
data(){
return {
pData:"222222",
jsonData: {
info: 2
},
}
},
methods:{
changeTopData(){
this.pData = 'AAAAAAA';
// this.$set(this.jsonData, 'newKey', 'CCCCCC');
this.jsonData.hj='sssss';
// this.jsonData.info = 'YYYYYY';
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
<!-- 中间层 -->
<template>
<div>
<LowerVue></LowerVue>
</div>
</template>
<script>
import LowerVue from './LowerVue.vue';
export default {
components:{
LowerVue }
}
</script>
<!-- 底层 -->
<template>
<div>
孙子组件接受数据 {{ pData + '------' + JSON.stringify(jsonData) }}
</div>
</template>
<script>
export default {
// inject: ['pData','jsonData','uuu']
inject:{
pData:{
default: ""
},
jsonData:{
from: 'jsonData',
default: ()=>{}
},
hj:{
from: 'jsonData',//从其他名字的属性注入
default: ()=>{} //设置默认值
}
}
}
</script>
注意:简单类型数据使用provide/inject传值时,是非响应式数据,顶层组件中数据修改后,子孙组件不会自动变化。复杂类型数据传输时,是响应式数据(其中使用this.jsonData.hj='sssss'方式增加新的属性时,vue实例无法监听到)。
5. 使用vuex共享数据
vuex使用说明:Vuex基础知识-CSDN博客
6. 其他ref & $ref 、$nextTick
1). ref & $ref
ref定义组件标识,$ref获取组件,this.$ref.组件ref.data(method)调用组件中的数据或方法。通常配合$nextTick()使用,$nextTick作用将回调延迟到下次 DOM 更新循环之后执行。
<template>
<div id="app">
<SendMsgC ref="sendMsg"></SendMsgC>
<button @click="ac">触发子组件方法</button>
</div>
</template>
<script>
import SendMsgC from './components/SendMsgC.vue';
export default {
name: 'App',
components: {
SendMsgC
},
methods:{
ac(){
this.$nextTick(()=>{
this.$refs.sendMsg.sendMsgs();
});
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
3). 插槽slot
插槽,使组件中的结构可以进行自定义,在组件中使用<slot></slot>占位自定义内容。使用组件时,组件的起始标签和结束标签之间的内容会替换插槽。组件中<slot></slot>标签中的内容时后备内容,可以作为组件插槽的默认值。
1. 默认插槽
只有一个slot标签
<template>
<div>
<div>我是插槽组件头部</div>
<slot>我是后备内容</slot> <!-- 组件的slot默认值 -->
<div>我是插槽组件尾部</div>
</div>
</template>
<SlotV>第一个插槽<span v-color='colorD'>测试全局指令</span></SlotV>
<SlotV>第二个插槽<button @click="changeColor">修改指令颜色</button></SlotV>
<SlotV></SlotV>
2. 具名插槽
一个组件中有多个插槽时,需要使用name属性标识具体的插槽,使用时v-slot:插槽名。调用具名插槽组件时,需要分发给各个插槽的内容需要使<templete>包裹分发内容。v-slot:插槽名可以缩写为#。
<template>
<div>
<slot name="header">我是插槽组件头部</slot>
<slot name="body">我是后备内容</slot> <!-- 组件的slot默认值 -->
<slot name="footer">我是插槽组件尾部</slot>
</div>
</template>
<SlotV>
<template v-slot:header><span v-color='colorD'>测试全局指令</span></template>
<template v-slot:body><button @click="changeColor">修改指令颜色</button></template>
<template #footer><span v-color='colorD'>第一个插槽尾部</span></template>
</SlotV>
3. 插槽的作用域
父组件访问插槽组件中的数据,在插槽组件中,以添加属性的方式将数据注册到slot标签上,并将slot标签上注册的所有属性组成为一个对象。
父组件调用的时候,对于默认插槽可以直接使用#default=“接受对象变量名”接收数据;对于具名插槽需使用v-slot:插槽名=“接受对象变量名”接收数据。
父组件接收数据时,也可以对子组件传过来的数据对象进行解构,直接使用对象中的属性名接收特定数据,例如:v-slot:插槽名=“{ 插槽组件对象属性名 }”
<SlotV>
<template v-slot:header="vdata1"><span v-color='colorD'>测试全局指令{{ vdata1 }}</span></template>
<template v-slot:body="{ mvalue }"><button @click="changeColor">修改指令颜色{{ mvalue }}</button></template>
<template #footer="vdata3"><span v-color='colorD'>第一个插槽尾部{{ vdata3 }}</span></template>
</SlotV>
<!-- 插槽组件 -->
<template>
<div>
<slot name="header" :vData="vData" mvalue="我是值1">我是插槽组件头部</slot>
<slot name="body" :vData="vjsonData" mvalue="我是值2">我是后备内容</slot> <!-- 组件的slot默认值 -->
<slot name="footer" :vData="vcolorD" mvalue="我是值3">我是插槽组件尾部</slot>
</div>
</template>
<script>
export default {
name: 'SlotV',
data() {
return {
vData: "222222",
vjsonData: {
info: 2
},
vcolorD: 'red'
}
},
}
</script>
4) 组件缓存(keep-alive)
路由跳转后,缓存原来的页面。新页面返回后,回到跳转前的位置。
- includes(Array): 需要缓存的组件名称。
- excludes(Array): 不需要缓存的组件名称。
- max: 最多可以缓存的组件实例数量
页面缓存时触发的生命周期钩子函数
- activated: 组件被看到时触发
- deactivated: 组件失活时触发
<template>
<div id="app">
<div>
<!-- route内置,设置路由对应组件所在位置 -->
<keep-alive :includes="[menu1F, menu2F]">
<router-view></router-view>
</keep-alive>
</div>
</div>
</template>
<script>
export default {
name: 'App',
activated(){
console.info("页面激活了");
},
deactivated(){
console.info("页面失活了");
},
}
</script>
8. 路由VueRouter
路径和组件的对应关系。需要下载VueRouter模块才能使用。
官网地址:Vue Router 3.X版本
Vue Router | The official Router for Vue.js
使用注意:vue2对应的VueRouter3.X Vuex3.x;vue3对应的时VueRouter4.X Vuex4.x
1) 下载路由组件
#进入项目目录,安装模块
npm install vue-router@3.6.5
2)安装注册route
import Vue from 'vue'
import VueRouter from 'vue-router' //引入模块
Vue.use(VueRouter) //安装注册
const router = new VueRouter() //创建路由对象
new Vue({
render: h => h(App),
router:router //注入路由对象到vue实例, router:router可以简写为router
}).$mount('#app')
3) 创建需要的组件,并配置相应规则(建议组件放在views目录下)
在views目录下创建相应的组件文件,同时在route实例中定义路由规则
1. 定义路由规则
routes参数介绍:
- path: string, //路径
- component: Component; //页面组件
- name: string; // 命名路由-路由名称
- components: ( ComponentName | ()=>import('页面地址') ); // 命名视图组件
- redirect: string | Location | Function; // 路径重定向
- props: boolean | string | Function; // 路由组件传递参数
- alias: string | Array<string>; // 路由别名
- children: Array<RouteConfig>; // 嵌套子路由,在嵌套页面需要设置子路由出口,路由地址不需要包含父级路由地址(http://localhost:8080/secondM2)
- beforeEnter?: (to: Route, from: Route, next: Function) => void; // 路由单独钩子
- meta: any; // 自定义标签属性,比如:是否需要登录
- icon: any; // 图标// 2.6.0+
- caseSensitive: boolean; // 匹配规则是否大小写敏感?(默认值:false)
- pathToRegexpOptions: Object; // 编译正则的选项
- linkActiveClass: string , //模糊匹配类名
- linkExactActiveClass: string //精确匹配类名
- mode: 'hash' //路由模式,默认hash(http://localhost:8080/#/m1),history模式(地址中不包含# http://localhost:8080/m1)需要后端做相关配置(routes路由模式设置为history时后端配置-CSDN博客)
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
import Menu1 from "@/views/Menu1.vue";
import Menu2 from "@/views/Menu2.vue";
import Menu3 from "@/views/Menu3.vue";
import NotFound from "@/views/NotFound.vue";
import SecondMenu1 from "@/views/SecondMenu1.vue";
import SecondMenu2 from "@/views/SecondMenu2.vue";
const router = new VueRouter({
routes: [
{path: '/', redirect: '/m1'}, //重定向
{name: 'n1', path:'/m1', component: Menu1 ,
children:[
{path:'/secondM1', component: SecondMenu1 },
{path:'/secondM2', component: SecondMenu2 },
]
}, //path -- 导航路径下, component-- 组件路径
{path:'/m2/:words?', component: Menu2 },
{name: 'n3', path:'/m3/:words', component: Menu3 },
{path: '*', component: NotFound} //任意匹配
],
linkActiveClass: 'active', //模糊匹配类名
linkExactActiveClass: 'exact-active', //精确匹配类名
mode: 'history' //路由模式,默认hash,history模式需要后端做相关配置
})
export default router;
2. 使用<a>标签设置导航
<a href="#/m1?key=menu111111">菜单一</a>
注意:href中要有#/
3.使用声明式导航<router-link>
配置to参数,可以实现导航激活时高亮
.a.router-link-active: 模糊匹配,可以匹配多级菜单
.a.router-link-exact-active: 精确匹配,只能匹配一级菜单
<template>
<div id="app">
<div class="nav">
<!-- 声明式导航,等价<a href,且可以实现激活时高亮-->
<router-link to="/m1">菜单一</router-link>
<router-link to="/m2">菜单二</router-link>
<router-link to="/m3">菜单三</router-link>
</div>
<div>
<!-- route内置,设置路由对应组件所在位置 -->
<router-view></router-view>
</div>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
}
},
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
.nav a.router-link-active {
background-color: red;
}
</style>
注意:组件名称由两个单词组成,否则容易报错
4. 跳转传参
1)查询参数传参,适合传递多个参数
设置参数:to='/路径名?参数名=参数值&参数名=参数值'
接受参数:$route.query.参数名
2)动态路由传参,适合单个参数
配置动态路由的path: path:“/路径名/:参数名”(此时限制参数值必须传,不传参数值的时候会显示空白。参数名后加?可以去掉这个限制。)
跳转: to="/路径名/参数值"
接收参数: $route.params.参数名
routes: [
{path:'/m1', component: Menu1 }, //导航路径下
{path:'/m2/:words?', component: Menu2 },
{path:'/m3/:words', component: Menu3 } //path -- 导航路径下, component-- 组件路径
],
<div class="nav">
<!-- 声明式导航,等价<a href,且可以实现激活时高亮-->
<router-link to="/m1?key=menu111111">菜单一</router-link>
<router-link to="/m2">菜单二</router-link>
<router-link to="/m3/menu33333">菜单三</router-link>
</div>
<template>
<div>
菜单一{{ $route.query.key }}
</div>
</template>
<template>
<div>
菜单三{{ $route.params.words}}
</div>
</template>
5. 编程式导航-路由跳转及传参
<div>
<input v-model="pathSearch">
<button @click="routeChange">路由跳转</button>
</div>
1)path路径跳转
methods: {
routeChange(){
// this.$router.push('/m2');
this.$router.push({
path: '/m1',
query: {
key: '路由跳转1'
}
})
},
},
2)name跳转(适合路径较长的情况)
methods: {
routeChange(){
// this.$router.push({
// name: 'n1',
// query: {
// key: this.pathSearch
// }
// })
this.$router.push({
name: 'n3',
params: {
words: this.pathSearch
}
})
},
},
异常:重复点击按钮时会报错Avoided redundant navigation to current location: "/". NavigationDuplicated: Avoided redundant navigation to current location: "/".
解决方案:错误 “Avoided redundant navigation to current location...” 的解决方案-CSDN博客
4) 配置导航栏及路由出口
在vue实例挂载组件上配置路由导航,及组件出口
<template>
<div id="app">
<div class="nav">
<!-- 声明式导航,等价<a href,且可以实现激活时高亮-->
<router-link to="/m1?key=menu111111">菜单一</router-link>
<router-link to="/m2">菜单二</router-link>
<router-link to="/m3/menu33333">菜单三</router-link>
</div>
<div>
<!-- route内置,设置路由对应组件所在位置 -->
<router-view></router-view>
</div>
</div>
</template>
5)$router常用函数
- $router.back(): 返回上一页没有参数直接使用
- $router.go(n): 前进或后退n步
- $router.push(String|Object): 跳转