创建Vue项目
一 搭建Vue-cli脚手架
建议使用Yarn 命令
(1)安装node.js
进入node.js中文官网,根据系统下载对应的安装包,注意看清是32位还是64位操作系统
node -v // 可查看安装node的版本
(2) 安装 cnpm
安装:
npm install -g cnpm --registry=http://registry.npm.taobao.org
安装 yarn
npm install -g yarn
(3) 安装vue-cli脚手架构建工具
输入命令
cnpm install -g @vue/cli
vue -V // 可查看是否安装成功,成功则出现暗转vue的版本(V 需大写)
(4) 创建项目
输入命令
vue create vue vuelianxi // vuelianxi是vue项目的名字,随便起,但不能出现大写字母
接下来会出现
Please pick a preset: // 选择你所需要的vue版本
用上下键和空格键选择你所需要安装的配置
大概选择这些配置
回车!
回车!
回车!
回车!
回车!
这里是咨询你 是否要将刚才的配置存入一个模板,并进行命名,(方便下次使用如果配置一样的话)
回车! 等待安装…
启动项目命令:
cd (你项目名字的文件夹)
yarn serve
二 数据单向传递
1 MVVM设计模式
在MVVM设计模式中由3份部分组成
(1) M: Model 数据模型(保存数据,处理数据业务逻辑)
(2) V:View 视图(展示数据,与用户交互)
(3) VM:View Model 数据模型和视图的桥梁(M是中国人,V是美国人,VM就是翻译)
2 Vue中MVVM的划分
(1) 被控制的区域: View
(2) Vue实例对象: View Model
(3) 实例对象中的data: Model
3 Vue中数据的单向传递
我们把"数据"交给"Vue实例对象",Vue实例对象将数据交给"界面"
![在这里插入图片描述](https://img-blog.csdnimg.cn/18d4aee05f95486d98299bb662397f96.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA6LW35ZWl5ZCN5ZGi5ZWK,size_16,color_FFFFFF,t_70,g_se,x_16)
4 数据的双向传递 v-model 指令
只适用于 表单<input>,<textarea>和<select>元素上创建双向数据绑定.
5 常用指令 v-once
只渲染元素和组件一次
6 常用指令 v-cloak
最终的HTML被生成渲染之前会先显示模板内容,所以如果用户网络比较慢或者网页性能比较差,name用户会看到模板内容
解决方法: 利用v-cloak 配合[v-cloak]:{display:none}默认先隐藏未渲染的界面,等到生成HTML之后再重新渲染
[v-cloak] {
display: none;
}
<div v-cloak>
{{ message }}
</div>
7 常用指令 v-text v-html
(1) v-text就相当于innerText
插值的方式: 可以将指定的数据插入到指定的位置
会覆盖原有的内容
不会解析HTML
< div v-text="msg">vue</ div>
data(){
return{
msg:"学习vue"
}
}
(2) v-html就相当于innerHTML
会覆盖原有的内容
会解析HTML
< div v-html="msg">vue</ div>
data(){
return{
msg:"<span>我是span</span>"
}
}
8 常用指令 v-if (v-else/v-else-if * 比较消耗内存*)
如果v-if取值是true就渲染元素,如果不是就不渲染元素
如果条件不满足根本就不会创建这个元素
v-if可以从模型中获取数据
v-if也可以直接赋值一个表达式
v-else 不需要表达式
v-else 前一兄弟元素必须有 v-if 或 v-else-if
v-else v-if 和v-else中间不能插入内容
<div id="demo">
<!-- 第一种-->
<!-- <p v-if="bol">{{ name }}</p>
<p v-else>{{ msg }}</p> -->
<!-- 第二种-->
<p v-if="age >= 18">{{ name }}</p>
<p v-if="age < 18">{{ msg }}</p>
<!-- 第三种-->
<p v-if="chengji >= 80">优秀</p>
<p v-else-if="chengji >= 60">良好</p>
<p v-else>差</p>
</div>
data() {
return {
name: "小米",
msg: "<span>我是span</sapn>",
bol: false,
age:18,
chengji:88,
};
},
// 如果bol的值是true就执行v-if,如果是false,就执行v-esle
9 常用指令 v-show(占用内存比较小,适用于频繁的切换)
用作条件渲染,取值为true就显示,取值为false就不显示
<p v-show="show">我是段落1</p>
<p v-show="hidden">我是段落1</p>
data(){
return{
show:false,
hidden:true,
}
}
10 常用指令 v-for
相当于Js中的for-in循环,可以根据数据多次渲染元素
可以遍历 数组,字符,数字,对象,
<li v-for = (value, index) in list>{{value}}---{{index}}</li> <!-- value 是遍历的内容,index是索引 -->
data(){
return{
list:["张三","李四","王五","赵六"]
}
}
11-1 常用指令 v-bind
格式:
v-bind:属性名称="绑定的数据"
:属性名称="绑定的数据"
例如: <input type="text" v-bind:value="name">
<input type="text" :value="name">
data(){
return{
name:vue2,
}
}
特点:
赋值的数据类是任意一个合法的JS表达式
例如: :属性名称="age + 1"
<input type="text" :value="age+1">
data(){
return{
name:vue2,
age:18,
}
}
11-2 v-bing 绑定类名
默认情况下,v-bind回去Model中查找数据
例如:< style>
.size{
font-size:150px;
}
.color{
background:red;
}
< /style>
< p :class="['size']"></ p> //类名需用[]括起来,里面加引号,注意单双引号使用问题
通过三目运算符来实现按需绑定
格式:{条件表达式 : ? ‘类名’ : ’ '}
例如:< style>
.size{
font-size:150px;
}
.color{
background:red;
}
.active{
color:blue;
}
< /style>
< p :class="['size','color',flag ? 'active' : '']"></ p>
data(){
flag:true, // true 类名生效,false类名不生效
}
通过对象来决定是否需要绑定
格式:{‘类名’:布尔值true/false}
例如
< p :class="['size','color',{ 'active' : true}]"></ p> // true 类名生效,false类名不生效
可以通过Model中的对象来替换数组
例如: 方便从服务端动态获取是否要绑定样式
< p :class="obj"></ p>
data(){
flag:true, // true 类名生效,false类名不生效
obj:{
'size':true, // true 类名生效,false类名不生效
'color':true, // true 类名生效,false类名不生效
'active':false // true 类名生效,false类名不生效
}
}
11-3 样式绑定
(1) 只需要将样式代码放到对象中赋值给style即可,但是取值必须用引号括起来
<p :style="{color:'red'}">我是段落</p> // 注意单双引号使用问题
(2) 如果样式的名称带-,也必须用引号括起来才可以
<p :style="{color:'red','font-size':'100px'}">我是段落</p>
(3) model中保存多个样式对象,想将多个对象都绑定给style,name可以将多个对象放到数组中赋值给style即可
<p :style="[obj,obj1]">我是段落</p>
data() {
return {
obj: {
"font-size": "100px", // 有- 同样需要用引号括起来
color: "red",
},
obj1{
background:"blue",
},
};
},
12-1 常用指令v-on
(1) 如果是通过v-on来绑定监听事件,那么在指定事件名称的时候不需要写on 例如: onclick -> click
<p v-on:click="alert(123)"></p>
(2) 如果是通过v-on来绑定监听事件,那么在赋值的时候必须赋值一个回调函数的名称
<button v-on:click="myfun"></button>
methods:{
myfun(){
alert("点击button")
}
}
(3) 简写方式 用@ 来替换v-on
<button @click="myfun"></button>
12-2 常用指令 v-on 修饰符
(1) 如果想让事件监听的回调函数只执行一次,那么就可以用**.once**修饰符
<button v-on:click.once="myfun">按钮</button>
methods: {
myfun() {
alert("123");
},
},
(2) 如果想阻止元素的默认行为,那么可以使用**.prevent**修饰符
<button v-on:click.prevent="myfun">按钮</button>
(3)如果想阻止冒泡事件,那么可以使用**.stop**修饰符
<div class="a" @click="myfu1">
<div class="b" @click.stop="myfu2"> // 输出结果:3 2
<div class="c" @click="myfu3"></div>
</div>
</div>
methods: {
myfu1() {
console.log("1");
},
myfu2() {
console.log("2");
},
myfu3() {
console.log("3");
},
},
(4) 如果想让回调只要当前元素触发事件的时候执行,那么就可以使用***.self***修饰符
<div class="a" @click="myfu1">
<div class="b" @click.self="myfu2"> // 输出结果:点击a,只有事件1执行, 点击b,事件1,2执行,点击c,事件1,3执行
<div class="c" @click="myfu3"></div>
</div>
</div>
</div>
(5) 默认情况下是冒泡事件,如果想变成事件捕获,那么就需要使用.capture修饰符
<div class="a" @click.capture="myfu1">
<div class="b" @click.capture="myfu2">
<div class="c" @click.capture="myfu3"></div>
</div>
</div>
</div>
// 点击事件3,不加.capture结果为3,2,1,冒泡事件,加上.capture 结果为1,2,3.捕获事件
12-3 常用指令v-on 注意点
(1) 绑定回调函数名称的时候,后面可以写()可以不写
v-on:click='myfn'
v-on:click='myfn()'
(2) 可以给绑定的回调函数传递参数
v-on:click="myfn('lnj',33)"
methods:{
myfn(name,age){
console.log(name,age)
}
}
// 或者
v-on:click="myfn('lnj',33,$event)"
methods:{
myfn(name,age,e){ // 可以拿到原生的时间对象
console.log(name,age,e)
}
}
(3) 如果给绑定的函数中需要用到data中的数据必须加上this
v-on:click="myfn('lnj',33,$event)"
data(){
return{
name:张珊,
}
},
methods:{
myfn(name,age,e){ // 可以拿到原生的时间对象
console.log(this.name) // 输出结果:张珊
}
}
12-4 常用指令v-on 按键修饰符
按键码:
.enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right
<input v-on:keyup.enter="submit">
// 或者直接把enter改成keycode 比如F2等于113
<input v-on:keyup.113="submit"> // submit 事件名
还可以通过全局 config.keyCodes 对象自定义按键修饰符别名:
// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112
13 常用指令-自定义指令
directive方法接收两个参数:
(1) 第一个参数: 指令的名称
(2) 对象
在自定义指令的时候,在指定指令名称的时候,不需要写v-
指令可以在不同的生命周期阶段执行
bind : 指令被绑定到元素上的时候执行
inserted: 绑定指令的元素被添加到父元素上的时候调用
bind:
<p v-color>我是段落</p>
<script>
// 如果是vue-cli的话 还需要:
import Vue from "vue";
Vue.directive("color",{
// 这里的el就是被绑定指令的那个元素
bind:function(el){
el.style.color = "red";
}
})
</script>
inserted:
<p v-focus>我是段落</p>
<script>
// 如果是vue-cli的话 还需要:
import Vue from "vue";
Vue.directive("color",{
// 这里的el就是被绑定指令的那个元素
inserted: function (el) {
el.focus();
},
})
</script>
14 常用指令 - 自定义指令参数
获取自定义指令传递的参数
在执行自定义指令对应的方法的时候,出了会传递el给我们,还会传递一个对象给我们,在这个对象中就保存了指令传递过来的参数
直接传值:
<p v-color="'red'">我是段落</p>
<script>
// 如果是vue-cli的话 还需要:
import Vue from "vue";
Vue.directive("color",{
// 这里的el就是被绑定指令的那个元素
bind:function(el,obj){
// el.style.color = "red";
el.style.color =obj.value;
}
})
</script>
值在model中:
<p v-color="yanse">我是段落</p>
<script>
// 如果是vue-cli的话 还需要:
import Vue from "vue";
Vue.directive("color",{
// 这里的el就是被绑定指令的那个元素
bind:function(el,obj){
el.style.color =obj.value;
}
})
export default {
data() {
return {
yanse:'green',
};
},
}
</script>
15 常用指令-自定义局部指令
(1) 自定义全局指令的特点
在任何一个Vue实例控制的区域中 都可以使用
(2) 自定义局部指令的特点
只能在自定义的那个Vue实例中使用
例如: <p v-color="'red'">我是一大段段落</p>
<script>
// 专门用于存储监听事件回调函数
methods: { },
// 专门用于定义局部指令的 directives
directives: {
color: {
bind: function (el, obj) {
el.style.color = obj.value;
},
},
},
</script>
16 Vue 计算属性
(1) 插值语法特点
可以在{{ }}中编写合法的JaveScript表达式
<p>{{ (msg.split("").reveres(), join("")) }}</p>
<script>
export default {
data() {
return {
msg: "asdafgfgf",
};
},
};
</script>
(2) 虽然在定义计算属性的时候是一个函数返回的数据,但是在使用计属性的时候不能在计算属性名称后面加(),因为他是一个属性不是一个函数(方法)
特点: 只要返回的结果没有发生变化,那么计算属性就会被执行一次
应用场景: 由于计算属性会将返回的结果缓存起来,所以如果返回的数据不经常发生变化,那么使用计算属性的性能会比使用函数的性能高!
<!-- 只会执行一次 -->
<p>{{ msg2 }}</p>
<p>{{ msg2 }}</p>
<p>{{ msg2 }}</p>
<script>
export default {
data() {
return {
};
},
// 专门用于存储监听事件回调函数
computed:{
msg2:function(){
let res = "abcdefg".split("").reverse().join("");
return res;
}
}
};
</script>
(3) 函数:每次调用都会执行
<!-- 会执行三次 -->
<p>{{ msgl }}</p>
<p>{{ msgl }}</p>
<p>{{ msgl }}</p>
methods:{
msgl(){
let res = "abcdefg".split("").reverse().join("");
return res;
}
}
17 自定义全局过滤器
(1) 什么是过滤器?
- 过滤器和函数和计算属性一样都是用来处理数据的,但是过滤器一般用于格式化插入的文本数据
(2) 如何自定义全局过滤器?
- Vue.filter(“过滤器名称”,过滤器处理函数)
- **注意点:**默认情况下,处理数据的函数接收一个参数,就是要被处理的数据
(3) 如何使用全局过滤器?
- {{msg | 过滤器名称}}
- :value=“msg | 过滤器名称”
(4) 过滤器注意点:
- 只能子插值语法和v-bind中使用
- 过滤器可以连续使用
<template>
<div>
<!-- Vue会把name交给指定的过滤器处理之后,再把处理之后的结果插入到指定的元素中 -->
<p>{{ name | formatPrice1 | formatPrice2 }}</p>
</div>
</template>
<script>
data() {
return {
name: "qqqaa,rrraa,yyyaa,iiiaa,pppaa",
};
},
</script>
filter.js
import Vue from "vue";
Vue.filter("formatPrice1", function (value) {
value = value.replace(/aa/g, "啦啦啦");
console.log(value);
return value;
});
Vue.filter("formatPrice2", function (value) {
value = value.replace(/啦啦啦/g, "哈哈哈哈");
console.log(value);
return value;
});
18 自定义局部过滤器
(1) 自定义全局过滤器的特点
- 在任何一个Vue实例控制的区域中都可以使用
(2) 自定义局部过滤器的特点
- 只能在自定义的那个Vue实例中使用
<p>{{ name | format }}</p>
export default {
data() {
return {
name: "qqqaa,rrraa,yyyaa,iiiaa,pppaa",
};
},
methods: {},
// 这里是局部过滤器的内容
filters: {
format: function (value) {
value = value.replace(/aa/g, "哈哈嗝哈哈");
console.log(value);
return value;
},
},
};
19 Vue 过渡动画上
(1) 如何给Vue控制的元素添加过渡动画
- 1 将需要的执行动画的元素放到transition组件中
- 2 当transition组件中的元素显示时会自动查找 .v-enter / .v-enter-to / .v-enter-active类名
- 3 当transition组件中的元素隐藏时会自动查找 .v-leave / .v-leave-to / .v-leave-active 类名
- 4 我们只需要在 .v-enter 和 .v-leave中指定动画开始状态, 在.v-enter-active 和 .v-leave-active 中指定动画执行的状态,即可完成过渡动画
<template>
<div>
<button @click="toggle">我是按钮</button>
<transition><div class="box" v-show="isshow">1</div></transition>
</div>
</template>
<script>
export default {
data() {
return {
isshow: false,
};
},
methods: {
toggle() {
this.isshow = !this.isshow;
},
},
};
</script>
<style lang="less" scoped>
.box {
width: 200px;
height: 200px;
background: red;
}
.v-enter {
opacity: 0;
}
.v-enter-to {
opacity: 1;
}
.v-enter-active {
transition: all 3s;
}
.v-leave {
opacity: 1;
}
.v-leave-to {
opacity: 0;
}
.v-leave-active {
transition: all 3s;
}
</style>
20 过渡动画 注意点
1.transition注意点
- transition 中只能放一个元素 , 放多个元素无效
- 如果想给多个元素添加过渡动画,就必须创建多个transition组件
// 这样只能一个div有效果出来
<transition
><div class="box" v-show="isshow"></div>
<div class="box" v-show="isshow"></div
></transition>
// 这样才两个div才可以都有效果
<transition><div class="box" v-show="isshow"></div></transition>
<transition><div class="box" v-show="isshow"></div></transition>
2 初始化动画设置
- 默认情况下第一次进入的时候没有动画
- 如果想一进来就有动画, 可以通过给transition添加appear属性的方式, 告诉Vue第一次进入就需要显示动画
<transition appear><div class="box" v-show="isshow"></div></transition>
3 如何给多个不同的元素指定不同的动画
如果有不同的元素需要执行不同的过渡动画,那么我们可以通过给transition指定name的方式, 来指定"进入之前/进入之后/进入过程中, 离开之前/离开之后/离开过程中" 对应的类名,来实现不同的元素执行不同的过渡动画
<transition appear name="one"
><div class="box" v-show="isshow"></div
></transition>
<style lang="less" scoped>
.box {
width: 200px;
height: 200px;
background: red;
}
.one-enter {
opacity: 0;
}
.one-enter-to {
opacity: 1;
margin-left: 500px;
}
.one-enter-active {
transition: all 3s;
}
</style>
21 过渡动画中
1.当前过渡存在的问题
通过transition类名的方式确实能够实现效果,但是实现的过渡效果并不能保存动画之后的状态, 因为Vue内部的实现是在过程中动态绑定类名, 过程完成之后删除类名.所以不能保存最终的效果.
2.在Vue中如何保存过渡最终效果
通过Vue 提供的JS钩子函数来实现过渡动画
-
v-on:befor-enter = “beforEnter” 进入动画之前
-
v-on:enter = “enter” 进入动画执行过程中
-
v-on:after-enter = “afterEnter” 进入动画完成之后
-
v-on:enter-cancelled = “enterCancelled” 进入动画被取消
-
v-on:befor-leave = “beforLeave” 离开动画之前
-
v-on:leave = “leave” 离开动画执行过程中
-
v-on:after-leave = “afterLeave” 离开动画完成之后
-
v-on:leave-cancelled = “leaveCancelled” 离开动画被取消
3 . JS钩子实现过渡注意点:
- 在动画过程中必须写上el.offsetWidth 或者 el.offsetHeight
- 在enter和leave方法中必须调用done方法,否则after enter 和 after-leave 不会执行
- 需要添加初始动画,那么需要吧done方法包裹到setTimeout方法调用
<div>
<button @click="toggle">我是按钮</button>
<!-- 注意点: 虽然我们是通过JS钩子函数来实现过渡动画,但是Vue还是会去查找类名,所以为了不让Vue去查找类名,可以给transition添加V-bind:css="false" -->
<transition appear
v-bind:css="false"
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter"
><div class="box" v-show="isshow"></div
></transition>
</div>
methods: {
toggle() {
this.isshow = !this.isshow;
},
beforeEnter(el) {
// 进入动画执行过程之前
console.log("beforEnter");
console.log(el);
},
enter(el, done) {
// 进入动画执行过程中
console.log("enter");
console.log(el);
console.log(done);
// 注意点:动画执行完毕之后一定要调用done回调函数,否则后续的afterEnter钩子函数不会被执行
// done();
// 注意点: 如果想让元素一进来就有动画,那么最好延迟一下再调用done方法 还有,那不要忘记再transition里面添加appear属性,不然也是不会起作用的
setTimeout(function () {
done();
}, 0);
},
afterEnter(el) {
// 进入动画执行过程之后
console.log("afterEnter");
console.log(el);
},
},
22 过渡动画 Velocity 的使用
- 配合Velocity实现过渡动画
在Vue 中我们除了可以自己实现过渡动画以外, 还可以结合第三方框架实现过渡动画
2 导入Velocity 库
在动画执行过程钩子函数中编写Velocity动画
import Velocity from "velocity-animate";
export default {
data() {
return {
isshow: true,
};
},
methods: {
toggle() {
this.isshow = !this.isshow;
},
beforeEnter(el) {
console.log(el);
},
enter(el, done) {
console.log(el);
Velocity(el, { opacity: 1, marginLeft: "500px" }, 3000);
done();
},
afterEnter(el) {
console.log(el);
},
},
};
23 过渡动画 下
- 自定义类名动画
在Vue中除了可以使用 默认类名(v-xxx)来指定过渡动画
除了可以使用 自定义类名前缀(yyy-xxx)来指定过渡动画(transition name = “yyy”)
除了可以使用 JS钩子函数来指定过渡动画外
还可以使用自定义类名的方式来指定过渡动画
<transition
appear
enter-class="qian"
enter-active-class="zhong"
enter-to-class="hou"
><div class="box" v-show="isshow"></div
></transition>
<style lang="less" scoped>
.box {
width: 200px;
height: 200px;
background: red;
}
.qian {
opacity: 0;
}
.hou {
opacity: 1;
margin-left: 500px;
}
.zhong {
transition: all 3s;
}
</style>
24 过渡动画 animated
- 配合 Animate.css实现过渡动画
导入Animate.css库
在执行过程中的属性上绑定需要的类名
<transition appear
><div
class="box animate__animated animate__bounceInRight"
v-show="isshow"
></div
></transition>
import "animate.css";
25 v-for 注意点上
- v-for在渲染元素的时候, 会先查看缓存中有没有需要渲染的元素
- 如果缓存中没有需要渲染的元素,就会创建一个新的放到缓存中
如果缓存中有需要渲染的元素,就不会创建一个新的,而是直接复用原有的
注意点: 在vue 中只要数据发生了改变,那么就会自动重新渲染
26 v-for 注意点下
- v-for为了提升性能,在更新已渲染过的元素列表时, 会采用"就地复用"策略,也正是因为这个策略 , 在某些时刻会导致我们的数据混乱. 例如:在列表前面新增了内容
- 为了解决这个问题, 我们可以在渲染列表的内时候给每一个元素添加上一个独一无二的key, v-for 在更新已经渲染的元素列表时,会判断key是否相同, 如果不同则重新创建
- key属性的注意点: 不能使用index的作为key , 因为当列表的内容新增或者删除index都会发生变化, 这就导致了不能很好地复用没有发生改变的元素, 大大降低了渲染的效率.
27 列表动画
- 如何同时给多个元素添加过渡动画
通过transition可以给单个元素添加过渡动画
transition和transition-group 的用法一致, 只不过transition是给单个元素添加动画, transition-group是给多个元素添加动画
<template>
<div>
<form>
<input type="text" v-model="name" />
<input type="submit" value="添加" @click.prevent="add" />
</form>
<ul>
<transition-group appear>
<li
v-for="(persons, index) in person"
:key="index"
class="animate__animated animate__bounceInRight"
@click="del(index)"
>
<input type="checkbox" />
<span>{{ index }} --- {{ persons.name }}</span>
</li>
</transition-group>
</ul>
</div>
</template>
<script>
import "animate.css";
export default {
data() {
return {
name: "",
person: [
{ name: "zs", id: 1 },
{ name: "ls", id: 2 },
{ name: "ww", id: 3 },
],
};
},
methods: {
add() {
let lastPerson = this.person[this.person.length - 1];
let newPerson = { name: this.name, id: lastPerson.id + 1 };
this.person.unshift(newPerson);
this.name = "";
},
del(index) {
this.person.splice(index, 1);
},
},
};
</script>
28 transition-group 注意点
- 默认情况下transition-group会将动画的元素放到span标签中,我们可以通过tag属性来指定将动画元素放在什么标签中
- 如果删除或者添加的效果和预想的效果不统一,比如从头部添加一条数据, 但是效果显示在了最后一条上,这就需要检查下key的绑定,在这里,key值一定要绑定id, 而不能绑定index.
<template>
<div>
<form>
<input type="text" v-model="name" />
<input type="submit" value="添加" @click.prevent="add" />
</form>
<!-- <ul> -->
<!-- 注意点: tag在这里可以添加ul,这里添加之后就可以吧上面的父ul删了 -->
<transition-group appear tag="ul">
<li
v-for="(person, index) in person"
:key="person.id"
@click="del(index)"
>
<input type="checkbox" />
<span>{{ index }} --- {{ person.name }}</span>
</li>
</transition-group>
<!-- </ul> -->
</div>
</template>
<script>
import "animate.css";
export default {
data() {
return {
name: "",
id: 3,
person: [
{ name: "zs", id: 1 },
{ name: "ls", id: 2 },
{ name: "ww", id: 3 },
],
};
},
methods: {
add() {
this.id++;
// let lastPerson = this.person[this.person.length - 1];
let newPerson = { name: this.name, id: this.id };
// let newPerson = { name: this.name, id: lastPerson.id + 1 };
this.person.unshift(newPerson);
// this.person.push(newPerson);
this.name = "";
},
del(index) {
this.person.splice(index, 1);
},
},
};
</script>
<style lang="less" scoped>
li {
list-style: none;
}
.v-enter {
opacity: 0;
}
.v-enter-to {
opacity: 1;
}
.v-enter-active {
transition: all 3s;
}
.v-leave {
opacity: 1;
}
.v-leave-to {
opacity: 0;
}
.v-leave-active {
transition: all 3s;
}
</style>
三
29 Vue组件 全局组件
Vue两大核心: 1.数据驱动页面改变 2.组件化
-
什么是组件? 什么是组件化?
(1) 在前端开发过程中组件就是把一个很大的界面拆分为多个小的界面, 每一个小的界面就是一个组件
(2) 将大界面拆分成小界面就是组件化 -
组件化的好处
(1) 可以简化Vue实例的代码
(2) 可以提高复用性 -
Vue中如何创建组件?
(1) 创建组件构造器
(2) 注册已经创建好的组件
(3) 使用注册好的组件
<body>
<div id="app">
<!-- 使用注册好的组件 -->
<abc></abc>
</div>
<script>
// 1 创建组件构造器
let Profile = Vue.extend({
// 注意点: 在创建组件指定组件模板的时候, 模板只能有一个根元素
template:'<div><p>1234535</p> <span>asdasd</span></div> '
});
// 2 注册已经创建好的组件
// 第一个参数: 指定注册的组件的名称
// 第二个参数: 传入已经创建好的组件构造器
Vue.component( "abc", Profile )
new Vue({
el: "#app",
data: {
isshow: false,
},
mounted() { },
methods: { }
});
</script>
</body>
30 Vue组件 全局组件简写
- 编写组件的模板
- 注册组件,给组件起个名称,在对象里面告诉它组件对应的模板id
<body>
<div id="app">
<!-- 使用注册好的组件 -->
<abc></abc>
</div>
<!-- 1 编写组件的模板 -->
<template id="info">
<div><p>abcdefg</p> <span>简化</span></div>
</template>
<script>
//注册组件,给组件起个名称,在对象里面告诉它组件对应的模板id
Vue.component( "abc", {template:'#info'} )
</script>
</body>
31 Vue组件 局部组件
- 自定义全局组件特点
在任何一个Vue实例控制的区域中都可以使用 - 自定义局部组件特点
只能在自定义的那个Vue实例控制的区域中可以使用 - 如何自定义一个局部组件
在vue实例中新增componcnts:{}
在{}中通过key/vue形式注册组件
components:{
abc:{}
}
<div id="app1">
<abc></abc>
</div>
<div id="app2">
<abc></abc>
</div>
<template id="info">
<div><p>abcdefg</p> <span>简化</span></div>
</template>
<script>
let vue1 = new Vue({
el: "#app1",
data: {
isshow: false,
},
mounted() {},
methods: { }
});
let vue2 = new Vue({
el: "#app2",
data: {
isshow: false,
},
mounted() { },
methods: { },
components:{
"abc" :{template:'#info'}
}
});
</script>
32 Vue组件 data和methods
-
自定义组件中的data和methosd
Vue实例控制的区域相当于一个大的组件,在大的组件总 我们可以使用data和methods
而我们自定义的组件也是一个组件,所以在自定义的组件中也能使用data和methods -
自定义组件中data注意点:
在自定义组件中不能像在vue实例中一样直接使用data,而是必须通过返回函数的方式来使用data
<div id="app2">
<!-- 由于我们是在Vue实例控制区域中使用的函数
所以系统会去Vue实例中查找有没有对应的方法
所以我们需要在Vue实例中实现对应的方法 -->
<button @click="appFn">按钮1</button>
<abc></abc>
</div>
<template id="info">
<!-- 由于我们是在自定义的组件中使用了函数,所以系统会去自定义的组件中查找有没有对应的方法,所以我们需要在自定义的组件中实现对应的方法 -->
<div>
<button @click="abcFn">按钮2</button>
<p>abcdefg</p> <span>简化</span>
<p>{{data_value}}</p>
</div>
</template>
let vue2 = new Vue({
el: "#app2",
data: {
isshow: false,
},
mounted() {},
methods: {
appFn(){
alert("我是按钮1")
}
},
components:{
// 注意点: 在创建组件指定组件的模板的时候,模板只能有一个根元素
"abc" :{
template:'#info',
// 注意点: 虽然在自定义的组件中也可以使用data,但是在使用的时候,使用的方式和Vue实例中不太一样,在自定义组件中使用data必须赋值
// 一个函数,然后通过函数的返回值来定义有哪些数据
<script>
data(){
return{
data_value:"data数据",
}
},
methods:{
abcFn(){
alert("我是按钮2")
}
},
}
}
</script>
33 Vue组件 组件中的data
// 组件中的data如果不是通过函数返回的,那么多个组件就会共用一份数据,就会导致数据混乱
// 如果组件中的data 是通过函数返回的,那么每创建一个新的组件都会调用一次这个方法,
// 将这个方法返回的数据和当前创建的组件绑定在一起,就这样就有效的避免了数据混乱
<div id="app2">
<button @click="toggle">按钮</button>
<!-- <p v-if="show">dddd</p>
<p v-else>ccccc</p> -->
<abc v-if="show"></abc>
<cba v-else></cba>
</div>
<template id="cba">
<div>123 </div>
</template>
<template id="abc">
<div>456</div>
</template>
<script>
let vue2 = new Vue({
el: "#app2",
data: {
show:true,
},
methods: {
toggle(){
this.show = !this.show;
}
},
components:{
"abc" :{
template:'#abc',
},
"cba" :{
template:'#cba',
}
},
});
</script>
34 Vue组件 动态组件
-
什么是动态组件?
通过v-if / v-else-if / v-else确实能够切换组件
但是在Vue中切换组件还有另一种更专业的方式
component我们称之为动态组件,也就是,你让我显示谁我就显示谁 -
为什么可以通过v-if切换还要有component
因为component可以配合keep-alive 来保存被隐藏组件隐藏之前的状态
<div id="app2">
<button @click="toggle">按钮</button>
<keep-alive>
<component v-bind:is="name"></component>
</keep-alive>
</div>
<template id="cba">
<div>123 <input type="checkbox"></div>
</template>
<template id="abc">
<div>456</div>
</template>
<script>
let vue2 = new Vue({
el: "#app2",
data: {
name:"abc",
},
methods: {
toggle(){
this.name = this.name === "abc"?"cba":"abc";
}
},
components:{
"abc" :{ template:'#abc',},
"cba" :{ template:'#cba',}
},
});
</script>
35 Vue组件 组件动画
-
如何给组件添加动画?
给组件添加动画和过去给元素添加动画一样
如果是单个组件就使用transition,多个组件就使用transition-grop -
过渡动画注意点:
默认情况下进入动画和离开动画是同时执行的,如果想一个做完之后再做另一个,需要指定动画模式
in-out : 新元素先进行过渡,完成之后当前元素过渡离开
out-in : 当前元素先进行过渡,完成之后新元素过渡进入
<style>
.v-leave {opacity: 1; }
.v-leave-to {opacity: 0; }
.v-leave-active {transition: all 3s; margin-left: 400px; }
.v-enter { opacity: 0; margin-left: 400px; }
.v-enter-to {opacity: 1;}
.v-enter-active { transition: all 3s; }
</style>
</head>
<body>
<div id="app2">
<button @click="toggle">按钮</button>
<transition mode="out-in">
<keep-alive>
<component v-bind:is="name"></component>
</keep-alive>
</transition>
</div>
<template id="cba">
<div>123 <input type="checkbox"></div>
</template>
<template id="abc">
<div>456</div>
</template>
<script>
let vue2 = new Vue({
el: "#app2",
data: {
show:true,
name:"abc",
},
methods: {
toggle(){
this.name = this.name === "abc"?"cba":"abc";
}
},
components:{
"abc" :{ template:'#abc',},
"cba" :{ template:'#cba',}
},
});
</script>
36 Vue组件 父子组件
-
什么是父子组件?
在一个组件中定义了其他组件就是父子组件,其实局部组件就是最简单的父子组件,因为我们说过可以把Vue实例看做是一个大的组件,我们在vue实例中定义了局部组件,就相当于在大组件里面定义了小组件,所以局部组件就是最简单的父子组件 -
如何定义其他组件?
自定义组件中可以使用data,可以使用methods,当然自定义组件中也可以使用coponents,所以我们也可以在自定义组件中再定义其他组件.
<div id="app2">
<abc></abc>
</div>
<template id="abc">
<div><p>这是父组件</p> <son></son></div>
</template>
<template id="son">
<div><p>这是子组件</p></div>
</template>
<script>
let vue2 = new Vue({
el: "#app2",
data: { },
methods: { },
components:{
"abc":{
template:"#abc",
components:{
"son":{
template:"#son",
}
}
},
},
});
</script>
37 Vue组件 父子组件数据传递
-
父子组件传递?
在Vue中子组件是不能访问父组件的数据的,如果子组件想要访问父组件的数据, 必须通过父组件传递 -
如何传递?
(1) 在父组件中通过v-bind传递数据, 传递格式 v-bind: 自定义接收名称 = “要传递的数据”
(2) 在子组件中通过props:[‘自定义接收名称’]
<div id="app2">
<abc></abc>
</div>
<template id="abc">
<div>
<!-- 注意点: 组件是可以使用自己的数据的 -->
<p>{{name}}</p>
<p>{{age}}</p>
<!-- 注意点: 这里将父组件的name通过parent传递给子组件 -->
<son :parent="name" :age="age"></son>
</div>
</template>
<template id="son">
p
<div><p>这是子组件</p>
<!-- 这里通过parent使用了父组件传递过来的数据 -->
<p>{{parent}}</p>
<p>{{age}}</p>
</div>
</template>
<script>
let vue2 = new Vue({
el: "#app2",
data: {},
methods: {},
components:{
"abc":{
template:"#abc",
data(){
return{
age:33,
name:"张三",
}
},
components:{
"son":{
template:"#son",
// 这里通过parent接收了父组件传递过来的数据
props:['parent']
}
}
},
},
});
</script>
38 Vue组件 父子组件方法传递
-
父子组件方法传递?
在Vue中 子组件是不能访问父组件的方法的,如果子组件想要访问父组件的方法, 必须通过父组件传递 -
如何传递方法?
(1) 在父组件中通过v-on传递方法, 传递格式 v-on:自定义接收名称 = “要传递的方法”
(2) 在子组件中定义一个方法
(3) 在自定义方法中通过this.$emit(‘自定义接收名称’); 触发传递过来的方法
<div id="app2">
<abc></abc>
</div>
<template id="abc">
<div>
<button @click="say">这是按钮</button>
<son @parent="say"></son>
</div>
</template>
<template id="son">
<div>
<button @click="sonfn">这是子按钮</button>
<p>这是子组件</p>
</div>
</template>
<script>
let vue2 = new Vue({
el: "#app2",
data: { },
methods: {},
components:{
"abc":{
template:"#abc",
methods:{
say(){alert("123")}
},
components:{
"son":{
template:"#son",
// 注意点:和传递数据不同,如果传递的是方法,那么在子组件中不需要接收
// 如果传递的是方法,那么需要在子组件中自定义一个方法
// 如果传递的是方法,那么在组件中直接使用自定义的方法即可
// 如果传递的是方法,那么需要在子组件自定义的方法中通过this.$emit("自定义接收的名称")的方法来触发父组件传递过来的方法
methods:{
sonfn(){
this.$emit("parent")
}
}
}
}
},
},
});
</script>
39 Vue组件 子组件传递数据给父组件
如何将子组件数据传递给父组件?
既然我们可以在子组件中调用父组件的方法,那么我们就可以在调用方法的时候给方法传递参数,传递的参数,就是我们需要传递的数据
<script>
let vue2 = new Vue({
el: "#app2",
data: { },
methods: {},
components:{
"abc":{
template:"#abc",
methods:{
say(data){console.log(data);}
},
components:{
"son":{
template:"#son",
methods:{
sonfn(){
// 第一个参数:需要调用的函数名称
// 后续的参数:给调用的函数传递参数
this.$emit("parent","数据")
}
}
}
}
},
},
});
</script>
40 Vue组件 命名注意点
组件中的命名注意点:
- 注册组件的时候使用了"驼峰命名", 那么在使用时需要转换成"短横线分隔命名"
例如: 注册时: myFather → 使用时: my-father
- 在传递参数的时候如果想使用"驼峰名称", 那么就必须写"短横线分隔命名"
例如: 传递:parent-name="name" →接收时 : props:["parentName"]
- 在传递方法的时候不能使用"驼峰命名", 只能使用"短横线分隔命名"
例如: @parent-say = "say" → this.$emit("parent-say")
41 Vue组件 多级传递
数据和方法的多级传递
- 在Vue中如果儿子想使用爷爷的数据, 必须一层一层往下传递
- 在Vue中如果儿子想使用爷爷的方法, 必须一层一层往下传递
<div id="app">
<grandfather></grandfather>
</div>
<template id="grandfather">
<div>
<button @click="say">grandfather</button>
<p>{{name}}</p>
<father :fgname="name" @father="say"></father>
</div>
</template>
<template id="father">
<div>
<button @click="fasay">father</button>
<p>{{fgname}}</p>
<son :fname="fgname" @son="fasay"></son>
</div>
</template>
<template id="son">
<div>
<button @click="son">son</button>
<p>{{fname}}</p>
</div>
</template>
<script>
let vue2 = new Vue({
el: "#app",
components: {
"grandfather": {
template: "#grandfather",
data() {
return {
name: "123"
}
},
methods: {
say() {
console.log("我是爷爷中的方法");
}
},
components: {
"father": {
template: "#father",
props: ["fgname"],
methods: {
fasay() {
this.$emit("father")
}
},
components: {
"son": {
template: "#son",
props: ["fname"],
methods: {
son() {
this.$emit("son")
}
},
}
}
}
}
},
},
});
</script>
42 Vue组件 匿名插槽
<div id="app">
<father></father>
</div>
<template id="father">
<div>
<!-- 需求: 在使用子组件的时候给子组件动态的添加一些内容 -->
<son>
<!-- 注意点: 默认情况下是不能在使用子组件的时候,给子组件动态添加内容的
如果想在使用子组件的时候,给子组件动态添加内容,name就必须使用插槽
-->
<div>这是追加的内容</div>
</son>
</div>
</template>
<template id="son">
<div>
<div>我是头部</div>
<!-- 这里的slot标签就是插槽, 插槽其实就是一个坑, 只要有了这个坑,
那么使用者就可以根据自己的需求来填这个坑-->
<!-- 注意点: 插槽可以指定默认数据,如果使用者没有填这个坑, 那么就会显示默认数据,
如果使用者填了这个坑,那么就会利用使用者填坑的内容替换整个插槽
-->
<!-- 注意点: 插槽是可以指定名称的,默认情况下如果没有指定名称,我们称之为匿名插槽 -->
<!-- 匿名插槽的特点: 有多少个匿名插槽,填充的数据就会被拷贝几份
虽然我们可以指定多个匿名插槽,但在企业开发中推荐只写一个匿名插槽 -->
<slot>我是默认数据</slot>
<div>我是底部</div>
</div>
</template>
<script>
let vue2 = new Vue({
el: "#app",
components: {
"father": {
template: "#father",
methods: {},
components: {
"son": {
template: "#son",
methods: {},
}
}
}
}
});
</script>
43 Vue组件 具名插槽
- 什么是具名插槽?
默认情况下有多少个匿名插槽,我们填充的数据就会被拷贝多少份,这导致了所有插槽中填充的内容都是不一样的,那么如果我们想给不同的插槽中填充不同的内容,就可以使用具名插槽. - 具名插槽使用
通过插槽的name属性给插槽指定名称,在使用时可以通过slot="name"方式, 指定当前内容用于替换哪个插槽
注意点: 如果没有指定要替换哪个插槽的内容,则不会被替换
注意点: slot属性在Vue2.6中已经被废弃, Vue2.6之后使用v-slot指令替代slot属性
<template id="father">
<div>
<son>
<!-- 这里通过slot属性告诉Vue,当前的内容是要填充到哪一个插槽中的-->
<div slot="one">这是追加的内容1</div>
<div slot="two">这是追加的内容3</div>
</son>
</div>
</template>
<template id="son">
<div>
<div>我是头部</div>
<!-- 可以在定义插槽的时候给插槽添加有个name属性,通过这个name属性来指定插槽的名称,
如果插槽指定了名称,那么我们就称之为具名插槽 -->
<!-- 注意点:默认情况下填充的内容是不会被填充到具体插槽中的,
只要给填充的内容指定了要填充到哪一个具名插槽之后,
才会将填充的内容填充到具名插槽中 -->
<slot name="one">我是默认数据</slot>
<slot name="two">我是默认数据</slot>
<div>我是底部</div>
</div>
</template>
44 Vue组件 v-solt指令
什么是v-slot指令?
- v-slot指令是Vue2.6中用于替代slot属性的一个指令
- 在Vue2.6之前,我们通过slot属性告诉Vue当前内容填充到哪一个具名插槽
- 在Vue2.6开始, 我们通过v-slot指令告诉Vue当前内容填充到哪一个具名插槽
注意点: v-slot指令只能在template标签上.可以使用#号替代v-solt:
<template id="father">
<div>
<son>
<!-- 这里通过slot属性告诉Vue,当前的内容是要填充到哪一个插槽中的-->
<!-- <template v-slot:one> -->
<template #one>
<div>这是追加的内容1</div>
</template>
<template v-slot:two>
<div>这是追加的内容2</div>
</template>
</son>
</div>
</template>
<template id="son">
<div>
<div>我是头部</div>
<slot name="one">我是默认数据</slot>
<slot name="two">我是默认数据</slot>
<div>我是底部</div>
</div>
</template>
45 Vue组件 作用域插槽
- 什么是作用域插槽?
作用域插槽就是带数据的插槽, 就是让父组件在填充子组件插槽内容时也能使用子组件的数据 - 如何使用作用域插槽
- 在slot中通过 v-bind:数据=“数据名称” 方式暴露数据
- 在父组件中通过接收数据
- 在父组件的 中通过 作用域名称.数据名称 方式使用数据
<div id="app">
<father></father>
</div>
<template id="father">
<div>
<son>
<!-- 2 slot-scope="abc" 作用:接收子组件插槽暴露的数据 -->
<!-- 作用域插槽的应用场景: 子组件提供数据, 父组件决定如何渲染 -->
<template slot-scope="abc">
<div>这是追加的内容1{{abc.names}}</div>
<li v-for="(name,index) in abc.names">{{name}}</li>
</template>
</son>
</div>
</template>
<template id="son">
<div>
<div>我是头部</div>
<!-- 1 :names="names" 作用:将当前子组件的names数据暴露给子组件 -->
<slot :names="names">我是默认数据{{names}}</slot>
<slot name="two">我是默认数据</slot>
<div>我是底部</div>
</div>
</template>
<script>
let vue2 = new Vue({
el: "#app",
components: {
"father": {
template: "#father",
methods: {},
components: {
"son": {
template: "#son",
data(){
return{
names:["zs","ls","ww","zl"]
}
},
methods: {},
}
}
}
}
});
</script>
46 Vue组件 v-slot指令
- 在2.6.0中, 我们为具名插槽和作用域插槽引入了一个新的统一的语法(即 v-slot 指令),它取代了slot 和slot-scope
- 也就是说我们除了可以通过v-slot指令告诉Vue内容填充到哪一个具名插槽中,还可以通过v-slot指令告诉Vue如何接收作用域插槽暴露的数据
- v-slot: 插槽名称=“作用域名称”
<template id="father">
<div>
<son>
<!-- 2 slot-scope="abc" 作用:接收子组件插槽暴露的数据 -->
<!-- 作用域插槽的应用场景: 子组件提供数据, 父组件决定如何渲染 -->
<template v-slot="abc">
<div>这是追加的内容1{{abc.names}}</div>
<li v-for="(name,index) in abc.names">{{name}}</li>
</template>
<!-- #two v-slot的简写 -->
<template #two="abc">
<div>这是追加的内容1{{abc.names}}</div>
<li v-for="(name,index) in abc.names">{{name}}</li>
</template>
</son>
</div>
</template>
<template id="son">
<div>
<div>我是头部</div>
<!-- 1 :names="names" 作用:将当前子组件的names数据暴露给子组件 -->
<slot :names="names">我是默认数据{{names}}</slot>
<!-- name="two" 命名 -->
<slot name="two" :names="names">我是默认数据</slot>
<div>我是底部</div>
</div>
</template>
47 Vuex 基本使用
vuex 是Vue配套的公共数据管理工具,我们可以将共享数据保存到Vuex中,方便整个程序中的任何组件都可以获取和修改vuex中保存的数据.
- 导出vuex.js
- 创建Vuex对象
- 在组件中添加store的key保存vuex对象
- 在使用vuex中保存的共享数据的时候, 必须通过如下的格式来使用 this.$store.state.数据
48 VueX 修改共享数据
export default {
data() {},
state: {
isCollapse: false,
display: true,
},
// mutation 用于保存修改共享数据的方法
mutations: {
// 注意点: 在执行mutation中定义的方法的时候,系统会自动给这些方法传递一个state擦书
// state中就保存了共享数据
// 利用 this.$store.commit("定义的方法名称")
collapseMenu(state) {
state.isCollapse = !state.isCollapse;
},
disStyle(state, data) {
state.display = data;
},
},
};
49 Vuex getters属性
Vuex个getters属性就和组件的计算属性一样, 会将数据缓存起来, 只有数据发生变化才会重新计算
<div>
{{ this.$store.getters.formart }}
</div>
getters:{
formart(state){
return state.msg + "www.it666.com"
}
}
50 VueRouter 基本使用
- 什么是Vue Router?
Vue Router和v-if/v-show一样,是用来切换组件的显示的
v-if / v-show 是用来切换(true / false)
Vue Router用哈希来切换(# / xxx)
比v-if / v-show 强大的是Vue Router 不仅仅能够切换组件的显示,还能够在切换的时候传递参数 - Vue Router使用
(1) 导入Vue Router
(2) 定义路由规则
(3) 根据路由规则创建路由对象
(4) 将路径对象挂载到Vue实例中
(5) 修改URL哈希值
(6) 通过 渲染匹配的组件
<div id="app">
<a href="#/one">切换到第一个界面</a>
<a href="#/two">切换到第二个界面</a>
<router-view></router-view>
</div>
<template id="one">
<div class="onepage"><p>我是第一个界面</p></div>
</template>
<template id="two">
<div class="twopage"> <p>我是第二个界面</p></div>
</template>
<script>
// 1. 定义组件
const one = {
template: "#one"
};
const two = {
template: "#two"
};
// 2. 定义切换的规则(定义路由规则)
const routes = [
// 数组中的每一个对象就是一条规则
{ path: '/one', component: one },
{ path: '/two', component: two },
];
// 3. 根据自定义的切换规则创建路由对象
const router = new VueRouter({
routes, // `routes: routes` 的缩写
})
let vue = new Vue({
el: "#app",
// 4. 将创建好的路由对象绑定到vue实例上
router:router,
components: {
one: one,
two: two,
}
});
</script>
51 VueRouter router-link
- 什么是router-link?
通过a标签确实能设置URL的hash,但是这种方式并不专业
在Vue Router中提供了专门用于设置hash的标签 router-link - router-link 特点
默认情况下Vue会将router-link渲染成a标签,但是我们可以通过tag来指定到底渲染成什么 - 给router-link设置选中样式
默认情况下我们可以通过重写router-link-active类名来实现设置选中样式
但是我们也可以通过linkActiveClass来指定选中样式 - 重定向路由
{path:‘被重定向值’, redirect:‘重定向之后的值’}
<style>
/* .router-link-active{
background: red;
} */
.nj-active{
background: rgb(89, 189, 214);
}
<div id="app">
<!-- <a href="#/one">切换到第一个界面</a> -->
<!-- <a href="#/two">切换到第二个界面</a> -->
<!-- 如果是通过router-link来设置URL的hash值, name不用写#,因为是通过to属性来设置hash值 -->
<!-- 默认情况下Vue在渲染router-link的时候,是通过a标签来渲染的
如果在企业开发中不想使用a标签来渲染, 那么可以通过tag属性来告诉vue通过什么标签来渲染 -->
<router-link to="/one" tag="button">切换到第一个界面</router-link>
<router-link to="/two" tag="button">切换到第二个界面</router-link>
<router-view></router-view>
</div>
<template id="one">
<div class="onepage">
<p>我是第一个界面</p>
</div>
</template>
<template id="two">
<div class="twopage">
<p>我是第二个界面</p>
</div>
</template>
<script>
// 1. 定义组件
const one = {
template: "#one"
};
const two = {
template: "#two"
};
// 2. 定义切换的规则(定义路由规则)
const routes = [
// 数组中的每一个对象就是一条规则
{ path: '/', redirect: "/one" }, // 重定向
{ path: '/one', component: one },
{ path: '/two', component: two },
];
// 3. 根据自定义的切换规则创建路由对象
const router = new VueRouter({
routes, // `routes: routes` 的缩写
linkActiveClass:"nj-active", // 自定义类名激活
})
let vue = new Vue({
el: "#app",
// 4. 将创建好的路由对象绑定到vue实例上
router: router,
components: {
one: one,
two: two,
}
});
</script>
</style>
51 Vue Router传递参数
只要将Vue Router挂载到Vue实例对象上, 我们就可以通过vue.$router拿到路由对象
只要能拿到路由对象, 就可以通过路由对象拿到传递的参数
- 通过URL参数(?key=value&key=value),通过this.$router拿到路由对象
- 通过占位符传递( 路由规则中:/key/:key, 路径中/value/value), 通过this.$router.params获取
<div id="app">
<!-- 第一种传递参数的方式: 通过URL参数的方式传递
在指定HASH的时候, 通过?key=value&key=value的方式传递
在传递的组件的生命周期方法中通过this.$route.query的方式获取 -->
<!-- 第二种传递参数的方式: 通过路由规则中的占位符传递
在指定路由规则的时候通过: /key/value/value的方式来传递值
在传递的组件的生命周期方法中通过 this.$route.params的方式来获取 -->
<router-link to="/one?name=lll&age=23" tag="button">切换到第一个界面</router-link>
<router-link to="/two/as/66" tag="button">切换到第二个界面</router-link>
<router-view></router-view>
</div>
<template id="one">
<div class="onepage">
<p>我是第一个界面</p>
</div>
</template>
<template id="two">
<div class="twopage">
<p>我是第二个界面</p>
</div>
</template>
<script>
// 1. 定义组件
const one = {
template: "#one",
created(){
console.log(this.$route);
}
};
const two = {
template: "#two",
created(){
console.log(this.$route);
}
};
// 2. 定义切换的规则(定义路由规则)
const routes = [
// 数组中的每一个对象就是一条规则
// { path: '/', redirect: "/one" }, // 重定向
{ path: '/one', component: one,value:["1","b"] },
{ path: '/two/:name/:age', component: two }, // 记得加冒号!!!
];
// 3. 根据自定义的切换规则创建路由对象
const router = new VueRouter({
routes, // `routes: routes` 的缩写
linkActiveClass:"nj-active", // 自定义类名激活
})
let vue = new Vue({
el: "#app",
// 4. 将创建好的路由对象绑定到vue实例上
router: router,
components: {
one: one,
two: two,
}
});
// console.log(vue.$router.options.routes[1]);
</script>
52 VueRouter 嵌套路由
什么是嵌套路由?
嵌套路由也称之为子路由, 就是在被切换的组件中又切换其他子组件
例如: 在one界面中又有两个按钮, 通过这两个按钮进一步切换one中的内容
<div id="app">
<router-link to="/one?name=lll&age=23" tag="button">切换到第一个界面</router-link>
<router-link to="/two/as/66" tag="button">切换到第二个界面</router-link>
<router-view></router-view>
</div>
<template id="one">
<div class="onepage">
<p>我是第一个界面</p>
<router-link to="/one/onesub1" tag="button">切换到第一个子界面</router-link>
<router-link to="/one/onesub2" tag="button">切换到第二个子界面</router-link>
<router-view></router-view>
</div>
</template>
<template id="two">
<div class="twopage">
<p>我是第二个界面</p>
</div>
</template>
<template id="onesub1">
<div class="twopage">
<p>我是第一个子界面</p>
</div>
</template>
<template id="onesub2">
<div class="twopage">
<p>我是第二个子界面</p>
</div>
</template>
<script>
const onesub1 = {
template:"#onesub1"
}
const onesub2 = {
template:"#onesub2"
}
// 1. 定义组件
const one = {
template: "#one",
components: {
onesub1: onesub1,
onesub2: onesub2,
},
created(){
console.log(this.$route);
}
};
const two = {
template: "#two",
created(){
console.log(this.$route);
}
};
// 2. 定义切换的规则(定义路由规则)
const routes = [
// 数组中的每一个对象就是一条规则
// { path: '/', redirect: "/one" }, // 重定向
{ path: '/one', component: one,
children:[
{
// 注意点: 如果是嵌套路由(子路由), 那么不用写一级路径的地址,并且也不用写/
path: 'onesub1', component: onesub1
},
{
path: 'onesub2', component: onesub2
}
]
},
{ path: '/two/:name/:age', component: two }, // 记得加冒号!!!
];
// 3. 根据自定义的切换规则创建路由对象
const router = new VueRouter({
routes, // `routes: routes` 的缩写
linkActiveClass:"nj-active", // 自定义类名激活
})
let vue = new Vue({
el: "#app",
// 4. 将创建好的路由对象绑定到vue实例上
router: router,
components: {
one: one,
two: two,
}
});
// console.log(vue.$router.options.routes[1]);
</script>
53 VueRouter 命名视图
什么是命名视图?
命名视图和前面讲解的具名插槽很像, 都是让不同的出口显示不同的内容,
命名视图就是当路由地址被匹配的时候同时指定多个出口, 并且每个出口中显示的内容不同
<div id="app">
<!-- 和匿名插槽一样, 如果指定了多个router-view, 那么当路由地址被匹配之后, 多个router-view中显示的内容是一样的 -->
<router-view name="name1"></router-view>
<router-view name="name2"></router-view>
</div>
<template id="one">
<div class="onepage">
<p>我是第一个界面</p>
</div>
</template>
<template id="two">
<div class="twopage">
<p>我是第二个界面</p>
</div>
</template>
</template>
<script>
// 1. 定义组件
const one = {
template: "#one",
};
const two = {
template: "#two",
};
// 2. 定义切换的规则(定义路由规则)
const routes = [
// 数组中的每一个对象就是一条规则
// { path: '/', redirect: "/one" }, // 重定向
{ path: '/',
components:{
name1 : one,
name2 : two,
}
},
{ path: '/two', component: two }, // 记得加冒号!!!
];
// 3. 根据自定义的切换规则创建路由对象
const router = new VueRouter({
routes, // `routes: routes` 的缩写
})
let vue = new Vue({
el: "#app",
// 4. 将创建好的路由对象绑定到vue实例上
router: router,
components: {
one: one,
two: two,
}
});
</script>
54 VueRouter watch属性
- 什么是Watch属性?
Watch属性是专门用于监听数据变化的, 只要数据发生了变化, 就会自动调用对应数据的回调方法 - Watch监听路由变化
Watch属性不仅仅能够监听数据的变化, 还能够监听路由地址的变化
在企业开发中我们可以通过Watch来判断当前界面是从哪跳转过来的
watch:{
"$router.path" : function(newValue , oldValue){
console.log(newValue, oldValue)
}
}
55 Vue生命周期方法 创建阶段
- 什么是生命周期方法?
和webpack生命周期方法一样, 都是丛生到死的特定阶段调用的方法
PS: 生命周期钩子 = 生命周期函数 = 生命周期事件 - 创建生命周期的方法
- beforeCreate:
- created:
- beforeMount:
- mounted:
- 运行期间的生命周期方法
- beforeUpdate:
- updated:
- 销毁期间的生命周期方法
- beforeDestroy:
- destroyed:
<template>
<div>
<p>{{ value }}</p>
<button @click="cc">点击</button>
</div>
</template>
<script>
export default {
data() {
return {
value: "学习",
};
},
beforeCreate() {
// 在调用beforeCreate的时候,仅仅表示Vue实例刚刚被创建出来
// 此时此刻还没有初始化好Vue实例中的数据方法,所以此时此刻还不能访问Vue实例中保存的数据和方法
// console.log(this.value);
// console.log(this.cc);
},
created() {
// 在调用created的时候, 是我们最早能够访问Vue实例中保存的数据和方法的地方
// console.log(this.value);
// console.log(this.cc);
},
beforeMount() {
// 在调用beforeMount的时候,表示Vue已经编译好了最终模板, 但是还没有将最终的模板渲染到界面上
console.log(document.querySelector("p").innerHTML);
console.log(document.querySelector("p").innerText);
},
mounted() {
// 在调用mounted的时候,表示Vue已经完成了模板的渲染, 表示我们已经可以拿到界面上渲染之后的内容了
console.log(document.querySelector("p").innerHTML);
console.log(document.querySelector("p").innerText);
},
methods: {
cc() {
console.log("vue");
},
},
};
</script>
56 Vue生命周期方法 运行阶段
beforeUpdate() {
// 在调用beforeUpdate的时候, 表示Vue实例中保存的数据被修改了
// 注意点: 只有保存的数据被修改了才会调用beforeUpdate, 否则不会调用
// 注意点: 在调用beforeUpdate的时候,数据已经更新了,但是界面还没有更新
console.log("beforUpdate");
},
update() {
// 在调用updated的时候,表示Vue实例中保存的数据被修改了, 并且界面也同步了修改的数据了,
// 也就是说: 数据和界面都同步更新之后就会调用updated
},
57 Vue生命周期方法 销毁阶段
beforeDestroy() {
// 在调用beforeDEstroy的时候, 表示当前组件即将被销毁了
// 注意点: 只有组件不被销毁, 那么beforeDestroy就不会 被调用
clearInterval(this.timer);
// this.timer = null;
// console.log("组件销毁");
},
destroyed() {
// 在调用destroyed的时候, 表示当前组件已经被销毁了
// 注意点: 只要组件不被销毁, 那么destroyed就不会调用
// 不要在这个生命周期方法中再去操作组件中数据和方法
console.log("2222");
},
58 Vue 特殊特性
- Vue特点: 数据驱动界面更新,无需操作DOM来更新界面
也就是说Vue不推荐我们直接操作DOM, 但是在企业开发中有时候我们确实需要拿到DOM操作DOM
那么如果不推荐使用原生的语法获取DOM, 我们应该如何获取DOM?
在Vue中 如果想要拿到DOM元素我们可以通过ref来获取 - ref使用
- 在需要获取元素上添加ref属性, 例如:
我是段落
- 在使用的地方通过 this. r e f s . x x x 获取 , 例如 : t h i s . refs.xxx 获取, 例如: this. refs.xxx获取,例如:this.ref.mypp
- 在需要获取元素上添加ref属性, 例如:
<p ref="my">我是DOM</p>
<p ref="my">{{ msg }}/p>
myFun(){
console.log(this.$refs.my.msg)
}