Vue知识总结
2021-06-17 14:52:04 2 举报
AI智能生成
Vue知识总结,带你巩固每一个Vue知识点
作者其他创作
大纲/内容
Vue的模板语法
插值表达式
如:{{name}}、{{ 1 + 5 }}
插值表达式中支持表达式
常用的指令
1. v-text 和 v-html
区别
v-html:可以将html中的内容渲染出来
v-text:不能将html中的内容渲染出来(原样输出),而是把html元素当成普通的字符串处理
2. v-pre
可以跳过编译过程,直接显示原始信息,即不会对内容进行变化,原样输出
如:<div v-pre>{{name}} --- {{age}}</div>, 编译输出{{name}} --- {{age}}
3. v-once
绑定数据,但是只绑定一次,当数据发生变化时,插值处的内容不会发生变化
如:<div v-once>{{name}} --- {{age}}</div>
4.v-on:为元素绑定事件
格式:v-on:事件名 或者 @事件名
如:<div v-on:click="xx">同意我帅就点我</div>或者<div @click="xx">点个赞</div>
v-on: 的执行函数要写在Vue 实例的methods:function{ alert(666) }方法中
5. 事件修饰符
.stop: 阻止事件的扩散
如:<div @click.stop="xx">同意我帅就点我</div>
.prevent: 阻止默认动作
如:<div @click.prevent="xx">同意我帅就点我</div>
6. v-bind: 绑定元素的属性
用法:v-bind:属性名="属性值"或者:属性名="属性值"
如:<a v-bind:helf="baidu">百度</a>或者<a :helf="baidu">百度</a>
v-bind中的属性值一般是vue实例的data中的数据。
注意v-bind: 一般绑定的是一个变量
7. 可以使用v-on 和 v-bind 实现数据的双向绑定
如:<input type="text" v-bind:value="name" v-on:keyup="xxx">
<div>{{name}}</div>
<div>{{name}}</div>
methods: {
xxx: function(e){
this.name = e.target.value;
}
}
xxx: function(e){
this.name = e.target.value;
}
}
8. 样式操作
操作字符串型的class属性
如:<div v-bind:class="'red'">点个赞</div>
使用对象格式处理class属性
如:<div v-bind:class="{blue: isBlue, big: isBig}">点个赞</div>
<button @click="changeBlue">变蓝</button>
<button @click="fontBig">字体变大</button>
<button @click="changeBlue">变蓝</button>
<button @click="fontBig">字体变大</button>
data: {
isBig: false,
isBlue: false
},
methods: {
fontBig: function(){
this.isBig = true
},
changeBlue: function(){
this.isBlue = true
}
}
isBig: false,
isBlue: false
},
methods: {
fontBig: function(){
this.isBig = true
},
changeBlue: function(){
this.isBlue = true
}
}
使用数组形式操作class属性
如:<div :class="[className]">点个赞</div>
<button @click="changeBlue">变蓝</button>
<button @click="cancel">恢复</button>
<button @click="changeBlue">变蓝</button>
<button @click="cancel">恢复</button>
data: {
className: ""
},
methods: {
changeBlue: function() {
this.className = "blue";
},
cancel: function() {
this.className = "";
}
}
className: ""
},
methods: {
changeBlue: function() {
this.className = "blue";
},
cancel: function() {
this.className = "";
}
}
使用对象和数组混合的形式操作class属性
如:<div :class="[blueClass, {big: isBig}]">点个赞</div>
<button v-on:click="changeBlue">变蓝</button>
<button v-on:click="fontBig">字体变大</button>
<button v-on:click="changeBlue">变蓝</button>
<button v-on:click="fontBig">字体变大</button>
data: {
blueClass: "",
isBig: false
},
methods: {
changeBlue: function() {
this.blueClass = "blue";
},
fontBig: function() {
this.isBig = true;
}
}
blueClass: "",
isBig: false
},
methods: {
changeBlue: function() {
this.blueClass = "blue";
},
fontBig: function() {
this.isBig = true;
}
}
简化操作class属性(数组操作)
如:<div :class="x1">点个赞</div>
<button @click="changeBlue">变蓝</button>
<button @click="changeBlue">变蓝</button>
data: {
x1: ["borderStyle", { big: true }]
},
methods: {
changeBlue: function() {
this.x1.push("blue");
}
}
x1: ["borderStyle", { big: true }]
},
methods: {
changeBlue: function() {
this.x1.push("blue");
}
}
简化操作class属性(对象操作)
如:<div :class="x2">点个赞</div>
<button @click="changeBlue">变蓝</button>
<button @click="changeSmall">变小</button>
<button @click="addBorder">加个边框</button>
<button @click="changeBlue">变蓝</button>
<button @click="changeSmall">变小</button>
<button @click="addBorder">加个边框</button>
data: {
x2: {
big: true,
blue: false
}
},
methods: {
changeBlue: function() {
this.x2.blue = true;
},
changeSmall: function() {
this.x2.big = false;
},
addBorder: function() {
this.x2.borderStyle = true;
this.$forceUpdate();
}
}
x2: {
big: true,
blue: false
}
},
methods: {
changeBlue: function() {
this.x2.blue = true;
},
changeSmall: function() {
this.x2.big = false;
},
addBorder: function() {
this.x2.borderStyle = true;
this.$forceUpdate();
}
}
注意事项:对于addBorder属性,在这里由于在data中没有对他进行任何操作,所以他属于我们在methods中动态添加的属性,因为动态添加的数据在这里不会自动更新数据,所以我们可以在methods中添加this.$forceUpdate()进行手动更新数据。
默认class的处理
所谓默认的class是指在使用`:class`添加class的时候,元素已经有了class
如:<div class="abc" v-bind:class="x3">点个赞</div>
<button @click="changeBlue">变蓝</button>
<button @click="changeBlue">变蓝</button>
data: {
x3: {
blue: false,
big: true
}
},
methods: {
changeBlue: function() {
this.x3.blue = true;
}
}
x3: {
blue: false,
big: true
}
},
methods: {
changeBlue: function() {
this.x3.blue = true;
}
}
操作style属性
如:<div style="height: 100px;" :style="x4">点个赞</div>
<button @click="changeBlue">变蓝</button>
<button @click="changeWidth">改变宽度</button>
<button @click="changeBlue">变蓝</button>
<button @click="changeWidth">改变宽度</button>
data: {
x4: {
// 键是css属性名,值是css属性值
backgroundColor: "",
width: "100px"
}
},
methods: {
changeBlue: function() {
this.x4.backgroundColor = "pink";
},
changeWidth: function() {
this.x4.width = "200px";
}
}
x4: {
// 键是css属性名,值是css属性值
backgroundColor: "",
width: "100px"
}
},
methods: {
changeBlue: function() {
this.x4.backgroundColor = "pink";
},
changeWidth: function() {
this.x4.width = "200px";
}
}
常见指令(表单)
数据的双向绑定:v-model
如:<div>{{name}}</div>
<input type="text" v-model="name">
<input type="text" v-model="name">
let vm = new Vue({
el: "#app",
data:{
name: '王大锤',
}
})
el: "#app",
data:{
name: '王大锤',
}
})
多行文本
如:<form action="">
<textarea cols="30" rows="10" v-model="remark"></textarea>
</form>
<textarea cols="30" rows="10" v-model="remark"></textarea>
</form>
let vm = new Vue({
el: "#app",
data: {
remark: '点个赞'
}
})
el: "#app",
data: {
remark: '点个赞'
}
})
行文本的绑定方式和单行文本的绑定方式完全一样
单选按钮
如: <div>
<input type="radio" value="0" v-model="shuai">帅
<input type="radio" value="1" v-model="shuai">丑
</div>
<input type="radio" value="0" v-model="shuai">帅
<input type="radio" value="1" v-model="shuai">丑
</div>
let vm = new Vue({
el: "#app",
data: {
shuai: 0
}
});
el: "#app",
data: {
shuai: 0
}
});
多个单选按钮可以绑定相同的变量,注意设置value
复选框
如:<div>
<input type="checkbox" value="1" v-model="hobby">
<input type="checkbox" value="2" v-model="hobby">
</div>
<input type="checkbox" value="1" v-model="hobby">
<input type="checkbox" value="2" v-model="hobby">
</div>
let vm = new Vue({
el: "#app",
data: {
hobby: [ ]
}
});
el: "#app",
data: {
hobby: [ ]
}
});
为多个复选框绑定相同的变量即可,但是该变量的值为一个数组
单选下拉列表
如:<div>
<select v-model="hobby">
<option value="1">学习Java从入门到放弃</option>
<option value="1">学习Vue从入门到大神</option>
</select>
</div>
<select v-model="hobby">
<option value="1">学习Java从入门到放弃</option>
<option value="1">学习Vue从入门到大神</option>
</select>
</div>
let vm = new Vue({
el: "#app",
data: {
hobby: 1
}
});
el: "#app",
data: {
hobby: 1
}
});
多选下拉列表
如:<div>
<select v-model="hobby" multiple="true">
<option value="1">学习Java从入门到放弃</option>
<option value="1">学习Vue从入门到大神</option>
</select>
</div>
<select v-model="hobby" multiple="true">
<option value="1">学习Java从入门到放弃</option>
<option value="1">学习Vue从入门到大神</option>
</select>
</div>
let v = new Vue({
el: '#test',
data: {
// 这里是个数组
hobby: []
}
});
el: '#test',
data: {
// 这里是个数组
hobby: []
}
});
将select的multiple属性设置为true,即可将select变成多选下拉,按住ctrl或者command键可以进行多选操作。vue中,多选下拉绑定的值的类型应为数组。
表单修饰符
.lazy
如:<form action="">
<div>
<input type="text" v-model="x1">
{{x1}}
</div>
<div>
<input type="text" v-model.lazy="x2">
{{x2}}
</div>
</form>
<div>
<input type="text" v-model="x1">
{{x1}}
</div>
<div>
<input type="text" v-model.lazy="x2">
{{x2}}
</div>
</form>
let v = new Vue({
el: '#test',
data: {
x1: '默认值',
x2: '默认值'
}
});
el: '#test',
data: {
x1: '默认值',
x2: '默认值'
}
});
在默认情况下,v-model 在每次 input 有内容变化时 将输入框的值与数据进行同步。如果添加 `lazy` 修饰符,则在元素失去焦点时才进行同步。
.number
如:<input v-model.number="age" type="number">
自动将用户的输入值转为数值类型
这通常很有用,因为即使在 type="number" 时,HTML 输入元素的值也总会返回字符串。如果这个值无法被 parseFloat() 解析,则会返回原始的值。
.trim
如:<input v-model.trim="msg">
自动过滤用户输入的首尾空白字符
常见指令(流程控制)
vue中提供的常见的分支结构指令有:v-if、v-else、v-else-if、v-show。
v-if、v-else、v-else-if的用法
如:<div id="app">
<div v-if="faceValue > 95">你长得好漂亮</div>
<div v-else-if="faceValue <= 94 && faceValue >= 85">你长得漂亮</div>
<div v-else-if="faceValue <= 84 && faceValue >= 75">漂亮</div>
<div v-else-if="faceValue <= 74">你长得有点感人</div>
</div>
<div v-if="faceValue > 95">你长得好漂亮</div>
<div v-else-if="faceValue <= 94 && faceValue >= 85">你长得漂亮</div>
<div v-else-if="faceValue <= 84 && faceValue >= 75">漂亮</div>
<div v-else-if="faceValue <= 74">你长得有点感人</div>
</div>
let vm = new Vue({
el: '#test',
data: {
faceValue: 100
}
})
el: '#test',
data: {
faceValue: 100
}
})
v-show 的用法
如:<div v-show="show">显示</div>
data: {
show: true
}
show: true
}
v-show可以控制元素是否显示到页面中
循环结构指令
使用 v-for 遍历数组
如:<ul>
<li v-for="i in hobby">{{i}}</li>
<li>********************************</li>
<li v-for="(value, index) in hobby">第{{index}}个值是: {{value}}</li>
<li>********************************</li>
<li v-for="item in firendgirls">{{item.name}}年龄是: {{item.age}}</li>
<li>********************************</li>
<li v-for="item in boys">{{item[0]}}的年龄是: {{item[1]}}</li>
</ul>
<li v-for="i in hobby">{{i}}</li>
<li>********************************</li>
<li v-for="(value, index) in hobby">第{{index}}个值是: {{value}}</li>
<li>********************************</li>
<li v-for="item in firendgirls">{{item.name}}年龄是: {{item.age}}</li>
<li>********************************</li>
<li v-for="item in boys">{{item[0]}}的年龄是: {{item[1]}}</li>
</ul>
data: {
hobby: ["游泳", "读书", "爬山", "绘画"],
firendgirls: [
{ name: "小花", age: 20 },
{ name: "小红", age: 18 },
{ name: "小黄", age: 22 }
],
boys: [
["小王", 25],
["小李", 24],
["小张", 23]
]
},
hobby: ["游泳", "读书", "爬山", "绘画"],
firendgirls: [
{ name: "小花", age: 20 },
{ name: "小红", age: 18 },
{ name: "小黄", age: 22 }
],
boys: [
["小王", 25],
["小李", 24],
["小张", 23]
]
},
注意:v-for 遍历中的key
在遍历的过程中,给每项元素设置一个唯一的key值,有助于提高vue的性能,对我们开发以及显示不会有任何影响。当然如果不设置key值 也可以,但是性能会略慢,所以推荐设置key值。
如:<li :key="index" v-for="(value, index) in hobby">第 {{ index }} 个值是:{{ value }}</li>
使用 v-for 遍历对象
如:<ul>
<li v-if="value != '女'" v-for="(value, key, index) in girl">
<span>{{value}}</span>
<span>{{key}}</span>
<span>{{index}}</span>
</li>
</ul>
<li v-if="value != '女'" v-for="(value, key, index) in girl">
<span>{{value}}</span>
<span>{{key}}</span>
<span>{{index}}</span>
</li>
</ul>
let v = new Vue({
el: '#test',
data: {
girl: {
name: '马冬梅',
age: 30,
sex: '女'
}
}
});
el: '#test',
data: {
girl: {
name: '马冬梅',
age: 30,
sex: '女'
}
}
});
v-show和 v-if、v-else、v-else-if 的区别
v-if、v-else、v-else-if:用来确定元素是否被渲染,相当于DOM元素的添加和删除。
v-show:控制的元素已经渲染,但是可能不显示,且性能开销小
Vue中对对象的更新检测
由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除,因此视图也无法自动的更新,但是怎么解决这种问题呢?来看例子
如:<ul>
<li v-for="(i, j) in girl">{{ i }} {{ j }}</li>
</ul>
<button @click="changeData" type="button">点击一下</button>
<li v-for="(i, j) in girl">{{ i }} {{ j }}</li>
</ul>
<button @click="changeData" type="button">点击一下</button>
data: {
girl: {
name: "小红",
age: 30
}
},
methods: {
changeData: function() {
// this.girl.age = 35;
this.girl.height = 165;
this.$forceUpdate();
}
}
girl: {
name: "小红",
age: 30
}
},
methods: {
changeData: function() {
// this.girl.age = 35;
this.girl.height = 165;
this.$forceUpdate();
}
}
从例子上可以看出,我们可以使用 this.$forceUpdate(); 把动态添加的数据渲染出来,这种用法虽然可以,但是比较耗费性能,那有没有其它的解决办法呢,往下看
如:<ul>
<li v-for="(i, j) in girl">{{ i }} {{ j }}</li>
</ul>
<button @click="changeData" type="button">点击一下</button>
<li v-for="(i, j) in girl">{{ i }} {{ j }}</li>
</ul>
<button @click="changeData" type="button">点击一下</button>
data: {
girl: {
name: "马冬梅",
age: 30
}
},
methods: {
changeData: function() {
Vue.set(this.girl, 'height', 165)
// Vue.set(this.girl, 'sex', '女');
// v.$set(v.girl, 'hobby', '演员')
}
}
girl: {
name: "马冬梅",
age: 30
}
},
methods: {
changeData: function() {
Vue.set(this.girl, 'height', 165)
// Vue.set(this.girl, 'sex', '女');
// v.$set(v.girl, 'hobby', '演员')
}
}
从上面例子中我们可以看出和数组一样使用的是Vue的静态方法set() 和 vue实例的 $set() 方法,推荐使用这两种方式进行类似的操作
Vue中对数组的更新检测
数组的变异方法
push()、pop()、shift()、unshift()、solt()、splice()、reverse()
数组的变异方法会改变调用了这些方法的原始数组,简单来说就是调用以上这些方法会改变原数组。
数组调用以上这些方法会自动触发视图更新,所谓视图自动更新,就是指当数据发生变化时,页面中渲染的内容也会跟着一起马上发生变化。
替换数组方法
filter()、concat()、slice()
所谓替换数组方法,就是指数组调用了该类方法的时候,并不会改变原始数组,而是会新创建一个新数组并返回
通过索引操作数组
通过对数组的索引去操作数组,vue并不能检测的到,因此视图也不会发生变化。因为索引会直接更改数组的值
解决方案
方法一
v.hobby , 被修改的值的索引) v.hobby: 表示被修改的数组
如:Vue.set(v.hobby, 1, '划船');
方法二
(v.hobby , 被修改的值的索引 , '被修改后的内容') v.hobby: 表示被修改的数组
如:v.$set(v.hobby, 2, '射箭')
示例
如:<ul>
<li v-for="i in hobby">{{ i }}</li>
</ul>
<button @click="changeData" type="button">点击一下</button>
<li v-for="i in hobby">{{ i }}</li>
</ul>
<button @click="changeData" type="button">点击一下</button>
let v = new Vue({
el: '#app',
data: {
hobby: ['游泳', '读书', '爬山', '绘画']
},
methods: {
changeData: function(){
// 这三种写法都可也,因为this就是指的v
this.$set(this.hobby, 1, '划划水');
v.$set(v.hobby, 2, '攀岩');
Vue.set(v.hobby, 3, '冲浪')
}
}
})
el: '#app',
data: {
hobby: ['游泳', '读书', '爬山', '绘画']
},
methods: {
changeData: function(){
// 这三种写法都可也,因为this就是指的v
this.$set(this.hobby, 1, '划划水');
v.$set(v.hobby, 2, '攀岩');
Vue.set(v.hobby, 3, '冲浪')
}
}
})
常见特性
计算属性
如:<input type="text" v-model="xxx">
<!-- 这里直接当属性使用,不用加括号 -->
<div>{{ yyy }}</div>
<!-- 这里直接当属性使用,不用加括号 -->
<div>{{ yyy }}</div>
data: {
xxx: ''
},
// 计算属性被定义到computed中,每个计算属性的值是个函数
computed: {
yyy: function(){
// 这里要有返回值
return this.xxx.split('');
}
}
xxx: ''
},
// 计算属性被定义到computed中,每个计算属性的值是个函数
computed: {
yyy: function(){
// 这里要有返回值
return this.xxx.split('');
}
}
计算属性的缓存
如:<input type="text" v-model="xxx">
<!-- 接下来使用3次计算属性 -->
<div>{{ yyy }}</div>
<div>{{ yyy }}</div>
<div>{{ yyy }}</div>
<!-- 接下来使用3次计算属性 -->
<div>{{ yyy }}</div>
<div>{{ yyy }}</div>
<div>{{ yyy }}</div>
data: {
xxx: ''
},
// 计算属性被定义到computed中,每个计算属性的值是个函数
computed: {
yyy: function(){
console.log('666');
return this.xxx.split('');
}
}
xxx: ''
},
// 计算属性被定义到computed中,每个计算属性的值是个函数
computed: {
yyy: function(){
console.log('666');
return this.xxx.split('');
}
}
计算属性 yyy 的对应的函数已经被执行过,并且数据被缓存起来,当后面再调用的计算属性 yyy 的时候,不需要再次执行函数。因此,对于比较复杂的逻辑或者需要多次使用的逻辑可以写到计算属性中,从而达到提高效率的目的。当变量 xxx 的值发生变化的时候会重新执行。
计算属性computed和 方法methods的区别
methods:方法会被多次调用,因此我们可以认为,默认情况下,方法的逻辑是不会被缓存的
侦听器
如:<input type="text" v-model="xxx">
<div>{{yyy}}</div>
<div>{{yyy}}</div>
data: {
// 变量的值发生变化的时候,会触发同名侦听器
xxx: '',
yyy: ''
},
watch: {
// 侦听器侦听的是和自己同名的变量,这里的侦听器名为xxx,侦听的 是data中的变量xxx的变化
// 侦听器接收的参数是data中变化后的值
xxx: function(value){
console.log(value);
this.yyy = value + '666'
}
}
// 变量的值发生变化的时候,会触发同名侦听器
xxx: '',
yyy: ''
},
watch: {
// 侦听器侦听的是和自己同名的变量,这里的侦听器名为xxx,侦听的 是data中的变量xxx的变化
// 侦听器接收的参数是data中变化后的值
xxx: function(value){
console.log(value);
this.yyy = value + '666'
}
}
侦听器主要用来侦听 data 中的数据的变化的,一旦侦听到数据的变化,就会触发侦听器中所定义的同名的方法,一般用在当数据变化的时候需要执行异步或者比较消耗资源的操作的时候。侦听器函数要写到 watch 中
过滤器
过滤器可以用在两个地方:插值表达式和 v-bind 表达式中
全局过滤器
Vue.filter( '过滤器的名称' , 过滤器的业务逻辑 (一般要有return) )
如:Vue.filter('toEnglish', function(val){
if(val == 0){
return 'woman';
}else{
return 'man';
}
})
if(val == 0){
return 'woman';
}else{
return 'man';
}
})
局部过滤器
将过滤器定义到一个vue实例中
如:<div>{{sex}}</div>
<!-- 使用过滤器 -->
<div>{{sex | toEnglish}}</div>
<!-- 使用过滤器 -->
<div>{{sex | toEnglish}}</div>
let v = new Vue({
el: '#test',
data: {
sex: 1
},
// 定义局部过滤器
filters: {
toEnglish: function (val) {
if (val == 0) {
return 'woman';
} else {
return 'man';
}
}
}
});
el: '#test',
data: {
sex: 1
},
// 定义局部过滤器
filters: {
toEnglish: function (val) {
if (val == 0) {
return 'woman';
} else {
return 'man';
}
}
}
});
带参数的过滤器
第一个参数表示要被处理的数据,给过滤器传递参数,则可以从第二个参数开始进行传递
如:<div>{{time | formatDate('Y-M-D h:m:s')}}</div>
<div>{{time | formatDate('Y-M-D')}}</div>
<div>{{time | formatDate('Y-M-D h:m')}}</div>
<div>{{time | formatDate('h:m:s Y-M-D')}}</div>
<div>{{time | formatDate('Y-M-D')}}</div>
<div>{{time | formatDate('Y-M-D h:m')}}</div>
<div>{{time | formatDate('h:m:s Y-M-D')}}</div>
let v = new Vue({
el: '#test',
data: {
// 13位时间戳
time: 1583762920282
},
// 定义局部过滤器
filters: {
// 第一个参数表示要被处理的数据
// 从第二个参数开始,表示使用过滤器时传递的参数
formatDate: function(val, arg){
let d = new Date(val);
let Y = d.getFullYear();
let M = d.getMonth() + 1;
let D = d.getDate();
let h = d.getHours();
let m = d.getMinutes();
let s = d.getSeconds();
return arg
.replace('Y',Y)
.replace('M',M)
.replace('D',D)
.replace('h',h)
.replace('m',m)
.replace('s',s)
}
}
}); 注:此代码只为了作说明,还有很大的改进空间
el: '#test',
data: {
// 13位时间戳
time: 1583762920282
},
// 定义局部过滤器
filters: {
// 第一个参数表示要被处理的数据
// 从第二个参数开始,表示使用过滤器时传递的参数
formatDate: function(val, arg){
let d = new Date(val);
let Y = d.getFullYear();
let M = d.getMonth() + 1;
let D = d.getDate();
let h = d.getHours();
let m = d.getMinutes();
let s = d.getSeconds();
return arg
.replace('Y',Y)
.replace('M',M)
.replace('D',D)
.replace('h',h)
.replace('m',m)
.replace('s',s)
}
}
}); 注:此代码只为了作说明,还有很大的改进空间
生命周期函数
vue 实例从创建到销毁,也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程。
在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会
在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会
目前vue提供了11个生命周期函数,相对常见的有8个,分别是
挂载阶段
beforeCreate、created、beforeMount、mounted)
更新阶段
( beforeUodate、updated)
销毁阶段
( beforeDestroy、destroyed )
基本用法
如:<div id="test">
{{x1}}
</div>
{{x1}}
</div>
let v = new Vue({
el: '#test',
data: {
x1: 123
},
beforeCreate: function () {
console.log('1');
},
created: function () {
console.log('2');
},
beforeMount: function () {
console.log('3');
},
mounted: function () {
console.log('4');
},
beforeUpdate: function () {
console.log('5');
},
updated: function () {
console.log('6');
},
beforeDestroy: function () {
console.log('7');
},
destroyed: function () {
console.log('8');
}
});
el: '#test',
data: {
x1: 123
},
beforeCreate: function () {
console.log('1');
},
created: function () {
console.log('2');
},
beforeMount: function () {
console.log('3');
},
mounted: function () {
console.log('4');
},
beforeUpdate: function () {
console.log('5');
},
updated: function () {
console.log('6');
},
beforeDestroy: function () {
console.log('7');
},
destroyed: function () {
console.log('8');
}
});
案例:ToDoList功能实现
https://blog.csdn.net/bigpatten/article/details/104989324
Vue的组件
Vue的全局组件和局部组件
顾名思义,所谓全局组卷简单来说就是定义再一个Vue实例的外面,在任何地方都可以使用
如:Vue.component('组件名称', {
// 组件内部的数据
// 注意这里是一个方法,可以使用箭头函数和简介语法,一定要有返 回值对象
data: function () {
return {
count: 0
}
},
template: '组件的模板内容'
});
// 组件内部的数据
// 注意这里是一个方法,可以使用箭头函数和简介语法,一定要有返 回值对象
data: function () {
return {
count: 0
}
},
template: '组件的模板内容'
});
局部组件就收一全局组件相反的组件,定义在Vue实例的里面
如:let C1 = new Vue({
el: '#test1',
// 定义局部组件
components: {"btn": {
data() {
return {
count: 0
}
},
// 在模板中可以使用其他组件
template: '<button v-on:click="count++">您点击了 {{ count }} 次. </button>'
}
}
});
let C2 = new Vue({
el: '#test2',
});
el: '#test1',
// 定义局部组件
components: {"btn": {
data() {
return {
count: 0
}
},
// 在模板中可以使用其他组件
template: '<button v-on:click="count++">您点击了 {{ count }} 次. </button>'
}
}
});
let C2 = new Vue({
el: '#test2',
});
关于组件的一些总结和注意点
1. 组件可以多次重负使用
2. 多次使用的组件之间是相互独立的
3. 其实一个Vue实例也是一个组件
4. 组件在使用时类似一一个自定义标签
如:上面例子中的 <btn>点一下</btn> 或者 <btn />
5. 组件不能直接使用,需要放到Vue实例或其它自建中才能使用,而这样就构成了父子组件
6. 组建的 template 的内容必须包含在一个根元素中(只能有一个跟标签),且支持ES6的模板语法
如:{
template: '<button v-on:click="count++">您点击了 {{ count }} 次. </button>'
}
template: '<button v-on:click="count++">您点击了 {{ count }} 次. </button>'
}
7. 一个组件也可以在另一个组件中使用
8. 对于驼峰命名的组件,如果直接在跟标签中使用,则要按照横线链接的方式
父子组件的划分
所谓父子组件,其实就是上下级关系,就比如 <ul> 和 <li> 一样
如:// 定义组件
Vue.component('my-button', {
data() {
return {
css: {color: 'blue'}
}
},
template: '<button><span :style="css">这是自定义组件</span> </button>'
});
// 定义组件
Vue.component('my-form', {
data() {
return {
test: '这是测试数据'
}
},
// 这里使用的有自定义组件
template: '<form><input type="text"><my-button></my-button> </form>'
}); //代码中 <my-form>就是<my-botton>的父组件,即<my-botton>时<my-form>的子组件
Vue.component('my-button', {
data() {
return {
css: {color: 'blue'}
}
},
template: '<button><span :style="css">这是自定义组件</span> </button>'
});
// 定义组件
Vue.component('my-form', {
data() {
return {
test: '这是测试数据'
}
},
// 这里使用的有自定义组件
template: '<form><input type="text"><my-button></my-button> </form>'
}); //代码中 <my-form>就是<my-botton>的父组件,即<my-botton>时<my-form>的子组件
组件插槽
所谓组件插槽,简单来说就是在子组件中预留一定的位置,父组件可以向该位置传递内容
基本使用
子组件预留的位置:<slot>默认内容<slot>
父组件向子组件分发内容:<组件名称>要分发的内容</组件名称>
示例:<div id="app">
<btn></btn>
<btn>点个赞</btn>
</div>
<btn></btn>
<btn>点个赞</btn>
</div>
Vue.component('btn', {
template: '<button><slot>点我</slot> </button>'
});
new Vue({
el: '#app',
});
template: '<button><slot>点我</slot> </button>'
});
new Vue({
el: '#app',
});
注: 如果使用子组件的时候没有传递数据,则使用子组件插槽的默认内容,如:<btn></btn>是” 点我 “。如果使用子组件的时候传递的有数据,则使用父组件传递的内容,如:“ <btn>我好帅</btn> ”
具名插槽:简单来说就是有名字的插槽,其父组件可以根据名字向子组件分发内容。
如:<xxx>
<div slot="first">学习Java从入门到放弃</div>
<div slot="second">数据库从删库到跑路</div>
<div slot="three">学习前端从入门到大神</div>
</xxx>
<div slot="first">学习Java从入门到放弃</div>
<div slot="second">数据库从删库到跑路</div>
<div slot="three">学习前端从入门到大神</div>
</xxx>
Vue.component("xxx", {
template: `<div>
<div style="color: red;">
<slot name="first"></slot>
</div>
<div style="color: green;">
<slot name="second"></slot>
</div>
<div style="color: blue;">
<slot name="three"></slot>
</div>
</div>`
});
new Vue({
el: "#app"
});
template: `<div>
<div style="color: red;">
<slot name="first"></slot>
</div>
<div style="color: green;">
<slot name="second"></slot>
</div>
<div style="color: blue;">
<slot name="three"></slot>
</div>
</div>`
});
new Vue({
el: "#app"
});
分发规则
父组件分发内容时,是按照名字分发到对应的插槽中,如果分发的内容没有名字,就是分发到无名字的子组件插槽。
使用 template 标签进行批量具名分发
<xxx>
<template>
<div slot="first">学习Java从入门到放弃</div>
<div slot="second">数据库从删库到跑路</div>
<div slot="three">学习前端从入门到大神</div>
</template>
</xxx> //这样同样可以达到上面代码的效果
<template>
<div slot="first">学习Java从入门到放弃</div>
<div slot="second">数据库从删库到跑路</div>
<div slot="three">学习前端从入门到大神</div>
</template>
</xxx> //这样同样可以达到上面代码的效果
作用域插槽
作用域插槽一般用在子组件的内容需要在父组件中处理的时候。
如:<xxx>
<template slot-scope="sonData">
<div v-if="sonData.king.camp == '蜀'" style="color: red;"> {{sonData.king.name}} -- {{sonData.king.camp}}</div>
<div v-else>{{sonData.king.name}} -- {{sonData.king.camp}} </div>
</template>
</xxx>
<template slot-scope="sonData">
<div v-if="sonData.king.camp == '蜀'" style="color: red;"> {{sonData.king.name}} -- {{sonData.king.camp}}</div>
<div v-else>{{sonData.king.name}} -- {{sonData.king.camp}} </div>
</template>
</xxx>
Vue.component('xxx', {
data(){
return {
kings:[
{name: '刘备', camp: '蜀'},
{name: '曹操', camp: '魏'},
{name: '孙权', camp: '吴'}
]
}
},
template: `<ul>
<!-- 子组件定义插槽的同时,绑定一个属性(名字自定), 绑定的数据可以被父组件捕获到 -->
<li v-for="i in kings"><slot :king="i">{{i.name}}</slot></li>
</ul>`
});
new Vue({
el: "#app"
});
data(){
return {
kings:[
{name: '刘备', camp: '蜀'},
{name: '曹操', camp: '魏'},
{name: '孙权', camp: '吴'}
]
}
},
template: `<ul>
<!-- 子组件定义插槽的同时,绑定一个属性(名字自定), 绑定的数据可以被父组件捕获到 -->
<li v-for="i in kings"><slot :king="i">{{i.name}}</slot></li>
</ul>`
});
new Vue({
el: "#app"
});
从例子中我们可以看出,在子组件中定义插槽的时候,可以绑定一个属性(名字自定),该属性绑定的数据可以被父组件捕获到
template: `<ul><li v-for="i in kings"><slot :king="i">{{i.name}}</slot></li></ul>`
在父组件中,可以通过 slot-scope 属性捕获到子组件绑定的数据,然后我们就可以自由的修改数据,修改后的数据会再次分发到子组件中
<xxx>
<!-- sonData是子组件绑定的数据,名字可以自己定 -->
<template slot-scope="sonData">
<!--这里的king就是子组件绑定的属性名,这个要一致-->
<span v-if="sonData.king.camp =='蜀'" style="color:red;"> {{sonData.king.name}}</span>
<span v-else>{{sonData.king.name}}</span>
</template>
</xxx>
<!-- sonData是子组件绑定的数据,名字可以自己定 -->
<template slot-scope="sonData">
<!--这里的king就是子组件绑定的属性名,这个要一致-->
<span v-if="sonData.king.camp =='蜀'" style="color:red;"> {{sonData.king.name}}</span>
<span v-else>{{sonData.king.name}}</span>
</template>
</xxx>
子主题
父子组件向子组件传值
父子组件向子组件传值:简单来说就是父子组件之间的通信
父组件向子组件发送数据:通过属性值,将数据传递给子组件
如:<div id="app">
<!--父组件通过绑定一个叫xxx的属性,向子组件传递一个“666”数据-->
<my-form :xxx='666'></my-form>
<!--父组件通过一个叫xxx的属性,向子组件传递一个“父级给的”数据-->
<my-form xxx="父级给的"></my-form>
</div>
<!--父组件通过绑定一个叫xxx的属性,向子组件传递一个“666”数据-->
<my-form :xxx='666'></my-form>
<!--父组件通过一个叫xxx的属性,向子组件传递一个“父级给的”数据-->
<my-form xxx="父级给的"></my-form>
</div>
子组件接收父组件传来的数据
如:Vue.component('my-form', {
// props数组中的值表示等待从父组件中接收的变量名,这个变量名 要和父组件传来的时候使用的属性名相同
props: ['xxx'],
template: '<form><input type="text" :value="xxx"></form>'
});
// props数组中的值表示等待从父组件中接收的变量名,这个变量名 要和父组件传来的时候使用的属性名相同
props: ['xxx'],
template: '<form><input type="text" :value="xxx"></form>'
});
示例
如:<div id="test">
<!-- 一次可以传递多个值 -->
<!-- 传递的属性可以直接写,也可通过绑定 -->
<son :xxx='"妈妈给的"' title='人民币'></son>
<son xxx="爸爸给的" :num='100'></son>
</div>
<!-- 一次可以传递多个值 -->
<!-- 传递的属性可以直接写,也可通过绑定 -->
<son :xxx='"妈妈给的"' title='人民币'></son>
<son xxx="爸爸给的" :num='100'></son>
</div>
// 定义组件
Vue.component('son', {
// 可以接收多个值,如果父级没有传递,则值为undefined
props: ['xxx', 'title', 'num'],
template: '<div>{{xxx}} ---- {{num}} ---- {{title}}</div>'
});
Vue.component('son', {
// 可以接收多个值,如果父级没有传递,则值为undefined
props: ['xxx', 'title', 'num'],
template: '<div>{{xxx}} ---- {{num}} ---- {{title}}</div>'
});
注意事项
由于html不区分大小写,父组件使用属性向子组件传值的时候,尽量不要用驼峰法,如果使用驼峰法,则子组件在接受的时候则要全按照小写处理。
如果父组件(标签中)使用属性向子组件传值的时候使用的是横线连接法, 则子组件在接收数据的时候,要用驼峰法。
如果在组件的`template`中向其子组件传递数据,则属性命名规则不受驼峰法限制。
在使用props传递数据时,一般是遵守`单向数据流原则`:只允许父组件将数据传递给子组件,不允许子组件直接修改这些数据。
props的数据验证
Vue.component('my-component',{
props:{
//必须是数字类型
propA: Number,
//必须是字符串或数字类型
propB:[String, Number],
//布尔值,如果没有定义,默认值就是true
propC:{
type: Boolean,
default: true
},
//数字,而且是必选
propD: {
type: Number,
required: true
},
//如果是数组或对象,默认值必须是一个函数来返回
propE: {
type: Array,
default: function () {
return {};
}
},
//自定义验证函数
propF: {
viladator: function (value) {
return value > 10;
}
}
}
});
props:{
//必须是数字类型
propA: Number,
//必须是字符串或数字类型
propB:[String, Number],
//布尔值,如果没有定义,默认值就是true
propC:{
type: Boolean,
default: true
},
//数字,而且是必选
propD: {
type: Number,
required: true
},
//如果是数组或对象,默认值必须是一个函数来返回
propE: {
type: Array,
default: function () {
return {};
}
},
//自定义验证函数
propF: {
viladator: function (value) {
return value > 10;
}
}
}
});
子组件向父组件传值
子组件是通过自定义事件的形式向父组件传递信息,具体来说就是:在子组件需要向父组件传值的时候,触发一个自定义事件,而在父组件中提前监听着该事件。
<div id="app">
<div :style="{color: xxx}">我很好</div>
<!-- 在父组件中监听自定义change-blue事件,并且该事件绑定的处 理程序是cb函数 -->
<son @change-blue="cb"></son>
</div>
<div :style="{color: xxx}">我很好</div>
<!-- 在父组件中监听自定义change-blue事件,并且该事件绑定的处 理程序是cb函数 -->
<son @change-blue="cb"></son>
</div>
Vue.component('son', {
// 当被点击的时候,使用$emit触发一个自定义事件
// 自定义事件的名称是change-blue(尽量不要用驼峰法,如果用 驼峰法,父组件触发的时候也还是要用横线连接)
template: `<button @click="$emit('change-blue')" type="button"> 变蓝</button>`
});
new Vue({
el: '#test',
data: {
xxx: 'red'
},
methods: {
cb: function(){
// 将父组件某个元素的颜色改成红色
this.xxx = 'blue'
}
},
});
// 当被点击的时候,使用$emit触发一个自定义事件
// 自定义事件的名称是change-blue(尽量不要用驼峰法,如果用 驼峰法,父组件触发的时候也还是要用横线连接)
template: `<button @click="$emit('change-blue')" type="button"> 变蓝</button>`
});
new Vue({
el: '#test',
data: {
xxx: 'red'
},
methods: {
cb: function(){
// 将父组件某个元素的颜色改成红色
this.xxx = 'blue'
}
},
});
在这个例子中,我们可以看出其子组件是这样做的
<!-- @click="$emit('change-blue') 子组件元素被点击的时候,使用$emit触发一个自定义事件 -->
template: `<button @click="$emit('change-blue')" type="button">变蓝</button>`
template: `<button @click="$emit('change-blue')" type="button">变蓝</button>`
父组件提前做好自定义组件的监听
<!-- change-blue 事件被触发的时候,调用cb函数 -->
<son @change-blue="cb"></son>
<son @change-blue="cb"></son>
子组件向父组件传值
<div id="app">
<div :style="{color: xxx}">我很好</div>
<!-- $event是固定用法,表示接收到的“来自自定义事件触发时传来 的数据”这里又将接收来的数据作为实参传递给cb函数-->
<son @change-blue="cb($event)"></son>
</div>
<div :style="{color: xxx}">我很好</div>
<!-- $event是固定用法,表示接收到的“来自自定义事件触发时传来 的数据”这里又将接收来的数据作为实参传递给cb函数-->
<son @change-blue="cb($event)"></son>
</div>
Vue.component('son', {
// 当被点击的时候,使用$emit触发一个自定义事件,$emit第二个 参数可以携带数据
template: `<button @click="$emit('change-blue', 'orange')" type="button">变蓝</button>`
});
new Vue({
el: '#test',
data: {
xxx: 'red'
},
methods: {
cb: function(x){
console.log(x);
// 用子组件传来的数据改变颜色
this.xxx = x
}
},
});
// 当被点击的时候,使用$emit触发一个自定义事件,$emit第二个 参数可以携带数据
template: `<button @click="$emit('change-blue', 'orange')" type="button">变蓝</button>`
});
new Vue({
el: '#test',
data: {
xxx: 'red'
},
methods: {
cb: function(x){
console.log(x);
// 用子组件传来的数据改变颜色
this.xxx = x
}
},
});
子组件如果想向父组件传值,可以通过`$emit`的第二个参数携带数据
<!-- @click="$emit('change-blue', 'gold')" 表示触发自定义事件并传递数据 -->
<button @click="$emit('change-blue', 'gold')" type="button">变蓝</button>
<button @click="$emit('change-blue', 'gold')" type="button">变蓝</button>
父组件这样接收数据
<!-- $event 是个固定用法, 表示从子组件中传来的数据,只能接收一个值(第二个) -->
<son @change-blue="cb($event)"></son>
<son @change-blue="cb($event)"></son>
兄弟组件之间的传值
在Vue中兄弟之间不能直接传值,我们可以通过设置一个事件中心的方式进行传值。简单来说就是事件中心就是一个媒介,由他实现兄弟之间的传值。
首先:我们要设置一个事件中心,就是一个Vue实例
let eventCenter = new Vue( );
然后是操作事件
监听事件
eventCenter.$on('事件名称','出发后要执行的函数');
触发事件
eventCenter.$emit('事件名称','携带的数据');
销毁事件
eventCenter.$off('事件名称')
示例
如:<liu-bei></liu-bei>
<zhang-fei></zhang-fei>
<!-- 销毁事件中心的事件后,则事件不可再被触发 -->
<button @click="kill" type="button">销毁事件</button>
<zhang-fei></zhang-fei>
<!-- 销毁事件中心的事件后,则事件不可再被触发 -->
<button @click="kill" type="button">销毁事件</button>
// 设置一个事件中心
let eventCenter = new Vue();
// 刘备组件
Vue.component("liu-bei", {
template: `<div><button @click="command" class="red" type='button'>刘备</button><span></span></div>`,
methods: {
command: function() {
// 触发张飞的自定义事件,并传递参数
eventCenter.$emit("obey", "三弟快断后");
}
}
});
// 张飞组件
Vue.component("zhang-fei", {
data() {
return {
commend: ""
};
},
template: `<div><button class="green" type='button'>张飞</button> <span>{{commend}}</span></div>`,
mounted: function() {
let x = this; //防止this的指向发生变化,当然这里也可以用 箭头函数
//生命周期函数: mounted,当模板挂载完毕后 通过事件中 心设置监听自定义事件
// 由于箭头函数中this表示上级的this,所以这地方更推荐 使用箭头函数
eventCenter.$on("obey", function(value) {
// 这个value参数是事件触发的时候传来的数据
console.log(value);
x.commend = "收到任务“" + value + "”,大哥放心保证完 成";
});
}
});
new Vue({
el: "#app",
methods: {
kill: function() {
// 销毁事件中心的自定义事件
eventCenter.$off("obey");
}
}
});
let eventCenter = new Vue();
// 刘备组件
Vue.component("liu-bei", {
template: `<div><button @click="command" class="red" type='button'>刘备</button><span></span></div>`,
methods: {
command: function() {
// 触发张飞的自定义事件,并传递参数
eventCenter.$emit("obey", "三弟快断后");
}
}
});
// 张飞组件
Vue.component("zhang-fei", {
data() {
return {
commend: ""
};
},
template: `<div><button class="green" type='button'>张飞</button> <span>{{commend}}</span></div>`,
mounted: function() {
let x = this; //防止this的指向发生变化,当然这里也可以用 箭头函数
//生命周期函数: mounted,当模板挂载完毕后 通过事件中 心设置监听自定义事件
// 由于箭头函数中this表示上级的this,所以这地方更推荐 使用箭头函数
eventCenter.$on("obey", function(value) {
// 这个value参数是事件触发的时候传来的数据
console.log(value);
x.commend = "收到任务“" + value + "”,大哥放心保证完 成";
});
}
});
new Vue({
el: "#app",
methods: {
kill: function() {
// 销毁事件中心的自定义事件
eventCenter.$off("obey");
}
}
});
动态组件
简单来说,动态组件就是能够在多个组件之间进行切换的组件
<!--组件占位符-->
<component></component>
<component></component>
<!-- 根据:is 指定组件名称,将对应的组件渲染到组件占位符中 -->
<component :is='xxx'></component>
<component :is='xxx'></component>
示例
如:<div id="test">
<div class="head">
<button @click="changeCity('meiguo')" type="button">美国</button>
<button @click="changeCity('faguo')" type="button">法国</button>
<button @click="changeCity('yindu')" type="button">印度</button>
</div>
<!-- 将对应的组件渲染到这面 -->
<component :is="currentCity"></component>
</div>
<div class="head">
<button @click="changeCity('meiguo')" type="button">美国</button>
<button @click="changeCity('faguo')" type="button">法国</button>
<button @click="changeCity('yindu')" type="button">印度</button>
</div>
<!-- 将对应的组件渲染到这面 -->
<component :is="currentCity"></component>
</div>
new Vue({
el: '#test',
data: {
currentCity: 'meiguo'
},
methods: {
changeCity: function(cityName){
this.currentCity = cityName;
}
},
components: {
meiguo: {
template: `<div class="body">我是美国</div>`
},
faguo: {
template: `<div class="body">我是英国</div>`
},
yindu: {
template: `<div class="body">我是印度</div>`
}
}
});
el: '#test',
data: {
currentCity: 'meiguo'
},
methods: {
changeCity: function(cityName){
this.currentCity = cityName;
}
},
components: {
meiguo: {
template: `<div class="body">我是美国</div>`
},
faguo: {
template: `<div class="body">我是英国</div>`
},
yindu: {
template: `<div class="body">我是印度</div>`
}
}
});
动态组建的缓存
默认情况下,切换动态组件,会重新渲染,这不仅会带来性能问题,同时也不能保持组件的状态,于是,于是我们使用动态组建的缓存将将给我们极大的方便。
实现动态组件的缓存非常简单,就是用一个<eep-alive></keep-alive>标签作为父级包括着我们定义的组件即可。
如上面例子中:<keep-alive>
<component :is="currentCity"></component>
</keep-alive>
<component :is="currentCity"></component>
</keep-alive>
注:keep-alive 目前支持3个属性分别是
exclude :名称匹配的组件不会被缓存,其值可以是字符串或者正则表达式
如:<keep-alive exclude="zhengzhou">
<!--除了名字叫zhengzhou的都会被缓存-->
<component :is="currentCity"></component>
</keep-alive>
<!--除了名字叫zhengzhou的都会被缓存-->
<component :is="currentCity"></component>
</keep-alive>
include:只有名称匹配的组件会被缓存,其值可以是字符串或者正则表达式
如:<keep-alive include="luoyang">
<!--只有名字叫luoyang的才会被缓存-->
<component :is="currentCity"></component>
</keep-alive>
<!--只有名字叫luoyang的才会被缓存-->
<component :is="currentCity"></component>
</keep-alive>
max:最多可以缓存多少个组件,其值是数字
如:<keep-alive max="2">
<!--最多缓存最近的2个组件-->
<component :is="currentCity"></component>
</keep-alive>
<!--最多缓存最近的2个组件-->
<component :is="currentCity"></component>
</keep-alive>
注意事项
值为正则表达式的时候,必须使用`v-bind`进行绑定
如:<keep-alive :include="/o/">
<component :is="currentCity"></component>
</keep-alive>
<component :is="currentCity"></component>
</keep-alive>
exclude 比 include 的优先级高,不支持字符串和正则
如:<keep-alive :include="/o/" exclude="zhengzhou">
<component :is="currentCity"></component>
</keep-alive>
<component :is="currentCity"></component>
</keep-alive>
需要匹配多个组件名称的时候,可以使用英文逗号,且中间不能有空格
如:<keep-alive include="zhengzhou,kaifeng">
<component :is="currentCity"></component>
</keep-alive>
<component :is="currentCity"></component>
</keep-alive>
Vue的路由
Vue-router的使用
使用Vue-router可以从一下7步入手,分别是
1.引入依赖文件
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
2.添加路由链接
<div id="app">
<p>
<!-- 使用 router-link 组件来导航.放置链接(url) -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<!-- to 属性默认会被渲染成href属性, to属性值默认会被渲染成以#开头的hash地址 -->
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
</p>
</div>
<p>
<!-- 使用 router-link 组件来导航.放置链接(url) -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<!-- to 属性默认会被渲染成href属性, to属性值默认会被渲染成以#开头的hash地址 -->
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
</p>
</div>
3.添加路由出口
<div id="app">
<!-- 路由出口,路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
<!-- 路由出口,路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
4.定义路由组件
// 这里是路由组件,其实就是路由实例的子组件
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
5.定义路由规则
const routes = [
// 注意这里是路由组件对象,不是字符串
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
// 注意这里是路由组件对象,不是字符串
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
6.创建路由实例
const router = new VueRouter({
// 这里是上一步创建的路由规则
routes // (缩写) 相当于 routes: routes
});
// 这里是上一步创建的路由规则
routes // (缩写) 相当于 routes: routes
});
7.将路由对象挂载到Vue根实例对象上
const app = new Vue({
el: '#app',
router
})
el: '#app',
router
})
注意:上面的第四、第五步可以写到第六步中
如://获取一个VueRouter实例
const router = new VueRouter({
//定义路由规则
routes: [
{
//引入路径path:
path: "/news",
//定义组件
component: {
//挂在模板
template: `
<div>这是首页</div>`
}
},
{
path: "/pages",
component: {
template: `
<div>这是详情页</div>`
}
}
]
});
const router = new VueRouter({
//定义路由规则
routes: [
{
//引入路径path:
path: "/news",
//定义组件
component: {
//挂在模板
template: `
<div>这是首页</div>`
}
},
{
path: "/pages",
component: {
template: `
<div>这是详情页</div>`
}
}
]
});
示例
如:<div id="app">
<h1>Hello App!</h1>
<p>
<!-- 使用 router-link 组件来导航. -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
</p>
<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
<h1>Hello App!</h1>
<p>
<!-- 使用 router-link 组件来导航. -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
</p>
<!-- 路由出口 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
</div>
// 0. 如果使用模块化机制编程,导入Vue和VueRouter,要调用 Vue.use(VueRouter)
// 1. 定义 (路由) 组件。
// 可以从其他文件 import 进来
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
// 2. 定义路由
// 每个路由应该映射一个组件。 其中"component" 可以是
// 通过 Vue.extend() 创建的组件构造器,
// 或者,只是一个组件配置对象。
// 我们晚点再讨论嵌套路由。
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
// 3. 创建 router 实例,然后传 `routes` 配置
// 你还可以传别的配置参数, 不过先这么简单着吧。
const router = new VueRouter({
routes // (缩写) 相当于 routes: routes
})
// 4. 创建和挂载根实例。
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
const app = new Vue({
el: '#app',
router
})
// 1. 定义 (路由) 组件。
// 可以从其他文件 import 进来
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }
// 2. 定义路由
// 每个路由应该映射一个组件。 其中"component" 可以是
// 通过 Vue.extend() 创建的组件构造器,
// 或者,只是一个组件配置对象。
// 我们晚点再讨论嵌套路由。
const routes = [
{ path: '/foo', component: Foo },
{ path: '/bar', component: Bar }
]
// 3. 创建 router 实例,然后传 `routes` 配置
// 你还可以传别的配置参数, 不过先这么简单着吧。
const router = new VueRouter({
routes // (缩写) 相当于 routes: routes
})
// 4. 创建和挂载根实例。
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
const app = new Vue({
el: '#app',
router
})
Vue Router的具体示例
有前面的例子我们便可以看出,假如由1千个路由组件,我们不可能定义1千次,于是引入动态路由将极大的方便我们的编程。
来看一个例子
如:<div id="app">
<!-- 1. 设置路由的链接地址 -->
<div class="nav">
<router-link to="/">首页</router-link>
<router-link to="/news/1">新闻1</router-link>
<router-link to="/news/2">新闻2</router-link>
<router-link to="/imgs">图片</router-link>
</div>
<!-- 2. 路由的组件的渲染位置 -->
<router-view></router-view>
</div>
<!-- 1. 设置路由的链接地址 -->
<div class="nav">
<router-link to="/">首页</router-link>
<router-link to="/news/1">新闻1</router-link>
<router-link to="/news/2">新闻2</router-link>
<router-link to="/imgs">图片</router-link>
</div>
<!-- 2. 路由的组件的渲染位置 -->
<router-view></router-view>
</div>
// 3. 获取一个路由实例
let News = {
template: '<div><h2>这是新闻页内容</h2></div>'
};
//定义路由规则
const router = new VueRouter({
routes: [
{
path: '/',
component: {
template: '<div><h2>这是首页内容</h2></div>'
}
},
{ path: '/news/:id', component: News },
{
path: '/imgs',
component: {
template: '<div><h2>这是图片页内容</h2></div>'
}
}
]
});
new Vue({
el: '#app',
// 4. 将路由实例挂载到Vue实例上
router
});
let News = {
template: '<div><h2>这是新闻页内容</h2></div>'
};
//定义路由规则
const router = new VueRouter({
routes: [
{
path: '/',
component: {
template: '<div><h2>这是首页内容</h2></div>'
}
},
{ path: '/news/:id', component: News },
{
path: '/imgs',
component: {
template: '<div><h2>这是图片页内容</h2></div>'
}
}
]
});
new Vue({
el: '#app',
// 4. 将路由实例挂载到Vue实例上
router
});
动态路由传参
方式1
在路由组件中使用`{{$route.params.id}}` 获取,注意这里的`id`是和前面的`:id`相对应的
如:let News = {
template: '<div><h2>这是新闻页{{$route.params.id}}内容</h2></div>'
};
template: '<div><h2>这是新闻页{{$route.params.id}}内容</h2></div>'
};
方式2
使用props传参的方式
// 设置 props: true
{ path: '/news/:id',
component: News,
props: true
}
{ path: '/news/:id',
component: News,
props: true
}
如:let News = {
// 使用props接收,这里的id要和前面的:id相对应
props: ['id'],
// 然后直接使用
template: '<div><h2>这是新闻页{{id}}内容</h2></div>'
};
// 使用props接收,这里的id要和前面的:id相对应
props: ['id'],
// 然后直接使用
template: '<div><h2>这是新闻页{{id}}内容</h2></div>'
};
方式3
使用props传参的方式(同时携带额外参数)
如:{ path: '/news/:id', component: News, props: xxx => ({name: '中国', id: xxx.params.id}) }
编程式导航
不同于<a>标签,我们之前应该用过location.href实现的页面跳转就是编程式导航。
在Vue Router中常见的API有
// 跳转到某个地址
this.$router.push('hash地址')
this.$router.push('hash地址')
// 前进或者后退 正整数表示前进,负数表示后退
this.$router.go(1)
this.$router.go(1)
比如在路由组件的时候
let News = {
props: ['id', 'name'],
template: `<div><a @click="goTo('/imgs')">去图片页</a> <h2>这是新闻页{{id}} -- {{name}}内容</h2></div>`,
methods: {
goTo: function(x){
this.$router.push(x)
}
},
};
props: ['id', 'name'],
template: `<div><a @click="goTo('/imgs')">去图片页</a> <h2>这是新闻页{{id}} -- {{name}}内容</h2></div>`,
methods: {
goTo: function(x){
this.$router.push(x)
}
},
};
命名路由
简单来说,就是给路由起个别名
如:{
path: '/imgs/:id',
// 在这里设置name属性,就给它起个别名了
name: 'tu',
component: {
template: '<div><h2>这是图片页内容</h2></div>'
}
}
path: '/imgs/:id',
// 在这里设置name属性,就给它起个别名了
name: 'tu',
component: {
template: '<div><h2>这是图片页内容</h2></div>'
}
}
命名路由的使用
给路由规则起过别名后,我们就可以在`<router-link>` 中动态的绑定`to`属性
如:<router-link :to="{name: 'tu', params: {id: 1}}">图片</router-link>
如果使用编程式导航,也可以使用类似的
如:this.$router.push({name: 'tu', params: {id: 1}});
路由的重定向
简单来说,就是改变路由的方向,让其指向另一个位置。
如:// 根路径直接强制跳转到 /imgs 路径
{ path: '/', redirect: '/imgs' }
{ path: '/', redirect: '/imgs' }
嵌套路由
如:<div id="app">
<!-- 设置主路由的链接地址 -->
<div class="nav">
<router-link to="/">首页</router-link>
<router-link to="/news">新闻</router-link>
</div>
<!-- 主路由的组件的渲染位置 -->
<router-view></router-view>
</div>
<!-- 设置主路由的链接地址 -->
<div class="nav">
<router-link to="/">首页</router-link>
<router-link to="/news">新闻</router-link>
</div>
<!-- 主路由的组件的渲染位置 -->
<router-view></router-view>
</div>
let News = {
template: ` <div>
<h2>这是新闻内容</h2>
<!-- 设置子路由的链接地址 -->
<router-link to="/news/SZ">时政新闻</router-link>
<router-link to="/news/YL">娱乐新闻</router-link>
<!-- 子路由的组件的渲染位置 -->
<router-view></router-view>
</div>`
};
let categoryNews = {
props: ['id'],
template: `<div><h4>这是{{id}}新闻内容</h4></div>`
}
const router = new VueRouter({
routes: [
{
path: '/',
component: {
template: '<div><h2>这是首页内容</h2></div>'
}
},
{
path: '/news',
component: News,
// 定义子路由规则
children: [
// 子路由规则
{path: '/news/:id', component: categoryNews, props: true}
]
}
]
});
new Vue({
el: '#app',
// 4. 将路由实例挂载到Vue实例上
router
});
template: ` <div>
<h2>这是新闻内容</h2>
<!-- 设置子路由的链接地址 -->
<router-link to="/news/SZ">时政新闻</router-link>
<router-link to="/news/YL">娱乐新闻</router-link>
<!-- 子路由的组件的渲染位置 -->
<router-view></router-view>
</div>`
};
let categoryNews = {
props: ['id'],
template: `<div><h4>这是{{id}}新闻内容</h4></div>`
}
const router = new VueRouter({
routes: [
{
path: '/',
component: {
template: '<div><h2>这是首页内容</h2></div>'
}
},
{
path: '/news',
component: News,
// 定义子路由规则
children: [
// 子路由规则
{path: '/news/:id', component: categoryNews, props: true}
]
}
]
});
new Vue({
el: '#app',
// 4. 将路由实例挂载到Vue实例上
router
});
注:嵌套路由中还可以继续嵌套,在children:[ ], 子路由中再写children:[ ], 子路由。
导航守卫
简单点,我们可以将导航守卫看作是一个Vue Router的生命周期函数
全局守卫
直接在路由实例上操作的钩子函数,它的特点是所有路由配置的组件都会触发该函数的执行,目前一共有3个全局钩子函数:`beforeEach`、`beforeResolve` 、`afterEach`
全局前置守卫(beforeEach)
一般用在路由还没跳转前执行,以免跳转了再执行而造成为时已晚。一般可以用来验证登录等操作。
基本语法:const router = new VueRouter({ ... })
// 注册一个守卫
router.beforeEach((to, from, next) => {
// ...
})
// 注册一个守卫
router.beforeEach((to, from, next) => {
// ...
})
to: Route 即将访问的路由对象
from: Route从哪个路由对象来的
next: Function该函数表示放行,可以有4种用法,常见的有3种用法:
next()直接放行
next('/user')跳转到 /user 路由
next(false)中断本次导航,重置到from路由对应的地址,相当于返回上一步
from: Route从哪个路由对象来的
next: Function该函数表示放行,可以有4种用法,常见的有3种用法:
next()直接放行
next('/user')跳转到 /user 路由
next(false)中断本次导航,重置到from路由对应的地址,相当于返回上一步
例如:const router = new VueRouter({
routes
})
// 设置导航守卫
router.beforeEach(function (to, from, next) {
console.log(to, from)
if (to.path === '/user') {
// 跳转到某个路由
return next('/login')
} else {
// 直接下一步
return next()
}
})
export default router
routes
})
// 设置导航守卫
router.beforeEach(function (to, from, next) {
console.log(to, from)
if (to.path === '/user') {
// 跳转到某个路由
return next('/login')
} else {
// 直接下一步
return next()
}
})
export default router
全局解析守卫(beforeResolve)和全局后置守卫(afterEach)
全局解析守卫
https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
全局后置守卫
https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
全局后置守卫
https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
路由独享守卫(beforeEnter)
路由独享守卫是针对某个路由规则而言的,它被定义在路由规则内
如:{
path: '/user',
component: User,
beforeEnter: (to, from, next) => {
}
}
path: '/user',
component: User,
beforeEnter: (to, from, next) => {
}
}
组件内的守卫
是指定义在组件内部的导航守卫,只针对该组件有效,它有3个钩子函数,分别是:beforeRouteEnter、beforeRouteUpdate和 beforeRouteLeave。
如:export default{
data(){
//...
},
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
data(){
//...
},
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
路由元信息
定义路由的时候可以配置 `meta` 字段
如:{
path: '/user',
component: User,
meta: {
title: '首页'
}
}
path: '/user',
component: User,
meta: {
title: '首页'
}
}
获取当前路由对象:console.log(this.$route)
再比如在导航守卫上使用
router.beforeEach(function (to, from, next) {
if (to.meta.title) {
document.title = to.meta.title
}
next()
})
if (to.meta.title) {
document.title = to.meta.title
}
next()
})
0 条评论
下一页