Vue + Vue-cli

创建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钩子实现过渡注意点:

  1. 在动画过程中必须写上el.offsetWidth 或者 el.offsetHeight
  2. 在enter和leave方法中必须调用done方法,否则after enter 和 after-leave 不会执行
  3. 需要添加初始动画,那么需要吧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 的使用

  1. 配合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);
    },
  },
};

贴一下Velocity的使用问题

23 过渡动画 下

  1. 自定义类名动画
    在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

  1. 配合 Animate.css实现过渡动画
    导入Animate.css库
    在执行过程中的属性上绑定需要的类名
 <transition appear
      ><div
        class="box animate__animated animate__bounceInRight"
        v-show="isshow"
      ></div
    ></transition>
    import "animate.css";

animate官方文档链接

25 v-for 注意点上

  1. v-for在渲染元素的时候, 会先查看缓存中有没有需要渲染的元素
  2. 如果缓存中没有需要渲染的元素,就会创建一个新的放到缓存中
    如果缓存中有需要渲染的元素,就不会创建一个新的,而是直接复用原有的
    注意点: 在vue 中只要数据发生了改变,那么就会自动重新渲染

26 v-for 注意点下

  1. v-for为了提升性能,在更新已渲染过的元素列表时, 会采用"就地复用"策略,也正是因为这个策略 , 在某些时刻会导致我们的数据混乱. 例如:在列表前面新增了内容
  2. 为了解决这个问题, 我们可以在渲染列表的内时候给每一个元素添加上一个独一无二的key, v-for 在更新已经渲染的元素列表时,会判断key是否相同, 如果不同则重新创建
  3. key属性的注意点: 不能使用index的作为key , 因为当列表的内容新增或者删除index都会发生变化, 这就导致了不能很好地复用没有发生改变的元素, 大大降低了渲染的效率.
    在这里插入图片描述

27 列表动画

  1. 如何同时给多个元素添加过渡动画
    通过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 注意点

  1. 默认情况下transition-group会将动画的元素放到span标签中,我们可以通过tag属性来指定将动画元素放在什么标签中
  2. 如果删除或者添加的效果和预想的效果不统一,比如从头部添加一条数据, 但是效果显示在了最后一条上,这就需要检查下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. 什么是组件? 什么是组件化?
    (1) 在前端开发过程中组件就是把一个很大的界面拆分为多个小的界面, 每一个小的界面就是一个组件
    (2) 将大界面拆分成小界面就是组件化

  2. 组件化的好处
    (1) 可以简化Vue实例的代码
    (2) 可以提高复用性

  3. 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组件 全局组件简写

  1. 编写组件的模板
  2. 注册组件,给组件起个名称,在对象里面告诉它组件对应的模板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组件 局部组件

  1. 自定义全局组件特点
    在任何一个Vue实例控制的区域中都可以使用
  2. 自定义局部组件特点
    只能在自定义的那个Vue实例控制的区域中可以使用
  3. 如何自定义一个局部组件
    在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

  1. 自定义组件中的data和methosd
    Vue实例控制的区域相当于一个大的组件,在大的组件总 我们可以使用data和methods
    而我们自定义的组件也是一个组件,所以在自定义的组件中也能使用data和methods

  2. 自定义组件中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组件 动态组件

  1. 什么是动态组件?
    通过v-if / v-else-if / v-else确实能够切换组件
    但是在Vue中切换组件还有另一种更专业的方式

    component我们称之为动态组件,也就是,你让我显示谁我就显示谁

  2. 为什么可以通过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组件 组件动画

  1. 如何给组件添加动画?
    给组件添加动画和过去给元素添加动画一样
    如果是单个组件就使用transition,多个组件就使用transition-grop

  2. 过渡动画注意点:
    默认情况下进入动画和离开动画是同时执行的,如果想一个做完之后再做另一个,需要指定动画模式
    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组件 父子组件

  1. 什么是父子组件?
    在一个组件中定义了其他组件就是父子组件,其实局部组件就是最简单的父子组件,因为我们说过可以把Vue实例看做是一个大的组件,我们在vue实例中定义了局部组件,就相当于在大组件里面定义了小组件,所以局部组件就是最简单的父子组件

  2. 如何定义其他组件?
    自定义组件中可以使用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组件 父子组件数据传递

  1. 父子组件传递?
    在Vue中子组件是不能访问父组件的数据的,如果子组件想要访问父组件的数据, 必须通过父组件传递

  2. 如何传递?
    (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组件 父子组件方法传递

  1. 父子组件方法传递?
    在Vue中 子组件是不能访问父组件的方法的,如果子组件想要访问父组件的方法, 必须通过父组件传递

  2. 如何传递方法?
    (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组件 命名注意点

组件中的命名注意点:

  1. 注册组件的时候使用了"驼峰命名", 那么在使用时需要转换成"短横线分隔命名"
例如: 注册时: myFather → 使用时: my-father
  1. 在传递参数的时候如果想使用"驼峰名称", 那么就必须写"短横线分隔命名"
	例如: 传递:parent-name="name" →接收时 : props:["parentName"]
  1. 在传递方法的时候不能使用"驼峰命名", 只能使用"短横线分隔命名"
	例如: @parent-say = "say" → this.$emit("parent-say")

41 Vue组件 多级传递

数据和方法的多级传递

  1. 在Vue中如果儿子想使用爷爷的数据, 必须一层一层往下传递
  2. 在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组件 具名插槽

  1. 什么是具名插槽?
    默认情况下有多少个匿名插槽,我们填充的数据就会被拷贝多少份,这导致了所有插槽中填充的内容都是不一样的,那么如果我们想给不同的插槽中填充不同的内容,就可以使用具名插槽.
  2. 具名插槽使用
    通过插槽的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组件 作用域插槽

  1. 什么是作用域插槽?
    作用域插槽就是带数据的插槽, 就是让父组件在填充子组件插槽内容时也能使用子组件的数据
  2. 如何使用作用域插槽
    • 在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指令

  1. 在2.6.0中, 我们为具名插槽和作用域插槽引入了一个新的统一的语法(即 v-slot 指令),它取代了slot 和slot-scope
  2. 也就是说我们除了可以通过v-slot指令告诉Vue内容填充到哪一个具名插槽中,还可以通过v-slot指令告诉Vue如何接收作用域插槽暴露的数据
  3. 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中保存的数据.
  1. 导出vuex.js
  2. 创建Vuex对象
  3. 在组件中添加store的key保存vuex对象
  4. 在使用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 基本使用

  1. 什么是Vue Router?
    Vue Router和v-if/v-show一样,是用来切换组件的显示的
    v-if / v-show 是用来切换(true / false)
    Vue Router用哈希来切换(# / xxx)
    比v-if / v-show 强大的是Vue Router 不仅仅能够切换组件的显示,还能够在切换的时候传递参数
  2. 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

  1. 什么是router-link?
    通过a标签确实能设置URL的hash,但是这种方式并不专业
    在Vue Router中提供了专门用于设置hash的标签 router-link
  2. router-link 特点
    默认情况下Vue会将router-link渲染成a标签,但是我们可以通过tag来指定到底渲染成什么
  3. 给router-link设置选中样式
    默认情况下我们可以通过重写router-link-active类名来实现设置选中样式
    但是我们也可以通过linkActiveClass来指定选中样式
  4. 重定向路由
    {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拿到路由对象
只要能拿到路由对象, 就可以通过路由对象拿到传递的参数

  1. 通过URL参数(?key=value&key=value),通过this.$router拿到路由对象
  2. 通过占位符传递( 路由规则中:/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属性

  1. 什么是Watch属性?
    Watch属性是专门用于监听数据变化的, 只要数据发生了变化, 就会自动调用对应数据的回调方法
  2. Watch监听路由变化
    Watch属性不仅仅能够监听数据的变化, 还能够监听路由地址的变化
    在企业开发中我们可以通过Watch来判断当前界面是从哪跳转过来的
watch:{
	"$router.path" : function(newValue , oldValue){
		console.log(newValue, oldValue)
	}
}

55 Vue生命周期方法 创建阶段

  1. 什么是生命周期方法?
    和webpack生命周期方法一样, 都是丛生到死的特定阶段调用的方法
    PS: 生命周期钩子 = 生命周期函数 = 生命周期事件
  2. 创建生命周期的方法
  • beforeCreate:
  • created:
  • beforeMount:
  • mounted:
  1. 运行期间的生命周期方法
    • beforeUpdate:
    • updated:
  2. 销毁期间的生命周期方法
    • 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 特殊特性

  1. Vue特点: 数据驱动界面更新,无需操作DOM来更新界面
    也就是说Vue不推荐我们直接操作DOM, 但是在企业开发中有时候我们确实需要拿到DOM操作DOM
    那么如果不推荐使用原生的语法获取DOM, 我们应该如何获取DOM?
    在Vue中 如果想要拿到DOM元素我们可以通过ref来获取
  2. ref使用
    • 在需要获取元素上添加ref属性, 例如:

      我是段落

    • 在使用的地方通过 this. r e f s . x x x 获取 , 例如 : t h i s . refs.xxx 获取, 例如: this. refs.xxx获取,例如:this.ref.mypp
<p ref="my">我是DOM</p>
<p ref="my">{{ msg }}/p>
myFun(){
	console.log(this.$refs.my.msg)
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值