Vue语法

1.vue模板语法2大类

插值语法:

  • 功能:用于解析标签内容

  • 用途:用于标签内容定义

  • 写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性

指令语法:

  • 功能:用于解析标签(包括:标签属性,标签内)

  • 用途:用于属性定义

  • 举例:v-bind:href=“xxx”或简写为:href=“xxx”,xxx同样要写js表达式,且可以直接读取到dta中的所有属性

代码

<div id="app">
    <p>{{msg}}</p>
    <a href="http://baidu.com">BUPT</a>
    <a v-bind:href="url">BUPT</a>
</div>
<script>
    var vm=new Vue({
    el:'#app',
    data:{
        msg:"ffff",
        url:"http://baidu.com"
        }
    })
</script>

2. el与data的两种写法

初识Vue:

  1. 想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象;

  2. root容器里的代码依然符合html规范,只不过混入了一些特殊的Vue语法;

  3. root容器里的代码被称为【Vue模板】;

  4. Vue实例和容器是一一对应的;

  5. 真实开发中只有一个Vue实例,并且会配合着组件一起使用;

  6. {{xxx}}中的xxx要写js表达式,且xxx可以自动读取到data中的所有属性;

  7. 一旦data中的数据发生改变,那么页面中用到该数据的地方也会自动更新;

注意区分:js表达式 和 js代码(语句)

1. 表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方:
            (1) a
            (2) a+b
            (3) demo(1)
            (4) x === y ? 'a' : 'b'
2. js代码(语句)
            (1) if(){}
            (2) for(){}

2.1 el有2种写法

  • new Vue时候配置el属性

  • 先创建Vue实例,随后再通过vm.$mount('#root')指定el的值

代码

<script>
    // 第一种  
    const vm = new Vue({        
        el:'#root',     
        data:{          
        name:'jack',
         }
    })
    // 第二种
    vm.$mount('#root')
</script>

2.2 data有2种写法

  • 对象式

  • 函数式

  • 在组件中,data必须使用函数式

2.3.一个重要的原则

由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了,而是window对象。

代码

<script> 
    new Vue({       
        el:'#root',
    // 第一种      
        data:{          
            name:'jack',
        } 
    // 第二种
        data(){ 
            return {   
                name: 'jack'   
            }       
        }
    })
</script>

完整代码如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>el与data的两种写法</title>
        <!-- 引入Vue -->
        <script type="text/javascript" src="../js/vue.js"></script>
    </head>
    <body>
        <!-- 准备好一个容器-->
        <div id="root">
            <h1>你好,{{name}}</h1>
        </div>
    </body>
    <script type="text/javascript">
        Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
        //el的两种写法
        /* const v = new Vue({
            //el:'#root', //第一种写法
            data:{
                name:'湖北理工'
            }
        })
        console.log(v)
        v.$mount('#root') //第二种写法 */
        //data的两种写法
        new Vue({
            el:'#root',
            //data的第一种写法:对象式
            /* data:{
                name:'湖北理工'
            } */
            //data的第二种写法:函数式
            //data:function(){  
            data(){
                console.log('@@@',this) //此处的this是Vue实例对象
                return{
                    name:'湖北理工'
                }
            }
        })
        如写成箭头函数,则this指向window
        new Vue({
            el:'#root',
            data:()=>{
                console.log('@@@',this)
                return{
                    name:'湖北理工'
                }
            }
        })
    </script>
</html>

3. methods

先写个methods的例子

<body>
    <div id="root">
        <h2>欢迎来到{{name}}学习</h2>
        <button v-on:click="showInfo">点我提示信息</button
    </div>
    <script>
        Vue.config.productionTip = false
    new Vue({
        el:'#root',
        data:{
            name:'湖北理工'
        },
        methods: {
           showInfo(){
                alert('同学!你好!')
            }
        },      
    })
   </script>
</body>

问题:

showInfo能否传递参数?对其加上参数后输出,可以看到形参a有输出为event。
showInfo(a,b,c,d){
    console.log(a,b,c,d)
}

e.target就是发生事件的事件目标,也即是button
showInfo(e){
    console.log(e.target.innerText)
}

可输出button上的文字。

this指针指向

showInfo(e){
	console.log(this)
}
//this指向vue实例。

v-on有简写形式如下

<div id="root">
	<h2>欢迎来到{{name}}学习</h2>
	<!-- <button v-on:click="showInfo">点我提示信息</button> -->
	<button @click="showInfo1">点我提示信息1(不传参)</button>
</div>

showInfo传参如下:

事件的基本使用: 1.使用v-on:xxx 或 @xxx 绑定事件,其中xxx是事件名; 2.事件的回调需要配置在methods对象中,最终会在vm上; 3.methods中配置的函数,不要用箭头函数!否则this就不是vm了; 4.methods中配置的函数,都是被Vue所管理的函数,this的指向是vm 或 组件实例对象; 5.@click="demo" 和 @click="demo($event)" 效果一致,但后者可以传参;

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>事件的基本使用</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>欢迎来到{{name}}学习</h2>
			<!-- <button v-on:click="showInfo">点我提示信息</button> -->
			<button @click="showInfo1">点我提示信息1(不传参)</button>
			<button @click="showInfo2($event,66)">点我提示信息2(传参)</button>
		</div>
	</body>
	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		const vm = new Vue({
			el:'#root',
			data:{
				name:'尚硅谷',
			},
			methods:{
				showInfo1(event){
					// console.log(event.target.innerText)
					// console.log(this) //此处的this是vm
					alert('同学你好!')
				},
				showInfo2(event,number){
					console.log(event,number)
					// console.log(event.target.innerText)
					// console.log(this) //此处的this是vm
					alert('同学你好!!')
				}
			}
		})
	</script>
</html>

事件修饰符

Vue中的事件修饰符: 1.prevent:阻止默认事件(常用); 2.stop:阻止事件冒泡(常用); 3.once:事件只触发一次(常用); 4.capture:使用事件的捕获模式; 5.self:只有event.target是当前操作的元素时才触发事件; 6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕;

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>事件修饰符</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>欢迎来到{{name}}学习</h2>
			<!-- 阻止默认事件(常用) -->
			<a href="http://www.hbpu.edu.cn" @click="showInfo">点我提示信息</a>
			<a href="http://www.atguigu.com" @click.prevent="showInfo">点我提示信息</a>
		</div>
	</body>
	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		new Vue({
			el:'#root',
			data:{
				name:'湖北理工学院'
			},
			methods:{
				showInfo(e){
                    //可去掉e.preventDefault(); //没有此行则会跳转,在@click后加上事件修饰符
                    e.preventDefault(); //没有此行则会跳转
					alert('同学你好!')
				}
			}
		})
	</script>
</html>

阻止事件冒泡:

<head>
	<meta charset="UTF-8" />
	<title>事件修饰符</title>
	<!-- 引入Vue -->
	<script type="text/javascript" src="../js/vue.js"></script>
    <style>
		*{
			margin-top: 20px;
		}
		.demo1{
			height: 50px;
			background-color: skyblue;
		}
	</style>
</head>
<body>
	<!-- 准备好一个容器-->
	<div id="root">
		<h2>欢迎来到{{name}}学习</h2>
		<!-- 阻止默认事件(常用) -->
		<a href="http://www.atguigu.com" @click.prevent="showInfo">点我提示信息</a>
        <!-- 阻止事件冒泡(常用) -->
		<div class="demo1" @click="showInfo">
         <!--先不加.stop,会冒泡,再加上.stop,则会阻止事件冒泡-->
	    <button @click.stop="showInfo">点我提示信息</button>  
        <!-- 事件只触发一次(常用)  在上面div中加入如下,则只会显示一次。--> 
		<button @click.once="showInfo">点我提示信息</button>
		<!-- 修饰符可以连续写 -->
		<a href="http://www.atguigu.com" @click.prevent.stop="showInfo">点我提示信息</a>
		</div>
	</div>
</body>

键盘事件

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>键盘事件</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>欢迎来到{{name}}学习</h2>
			<input type="text" placeholder="按下回车提示输入"  @keyup="showInfo">
		</div>
	</body>
	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		new Vue({
			el:'#root',
			data:{
				name:'湖北理工'
			},
			methods: {
				showInfo(e){
					console.log(e.target.value)
				}
			},
		})
	</script>
</html>
methods: {
    showInfo(e){
        if (e.keyCode !== 13)  return
        console.log(e.target.value)
    }
}

不用自己判断,去掉if (e.keyCode !== 13) return,可简化为

<input type="text" placeholder="按下回车提示输入" @keyup.enter="showInfo">

其中,.enter为按键别名。Vue中常用按键别名如下

  1. Vue中常用的按键别名: 回车 => enter 删除 => delete (捕获“删除”和“退格”键) 退出 => esc 空格 => space 换行 => tab (特殊,必须配合keydown去使用) 上 => up 下 => down 左 => left 右 => right 可在以上代码中换成其他按键别名尝试。 如没有这些按键别名,则需要自行定义。 tab键特殊,必须配合keydown去使用,因为tab键在按下时就跳离开了对应的元素。

  2. Vue未提供别名的按键,e.key,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名)

  3. 系统修饰键(用法特殊):ctrl、alt、shift、meta (1).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。 (2).配合keydown使用:正常触发事件。

    此时会每按次键在console中显示一次。但应该是所有内容输入完毕后再输出到console。 用JS完成如下

(1).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。

<input type="text" placeholder="按下回车提示输入" @keyup.ctrl="showInfo">

如果需要指定具体的组合,ctrl+y来触发,则写法如下

(2).配合keydown使用:正常触发事件。

<input type="text" placeholder="按下回车提示输入" @keydown.ctrl="showInfo">

修饰符可以连续写,既阻止跳转又阻止冒泡。修饰符顺序可以任意。

<!-- 阻止事件冒泡(常用) -->
<div class="demo1" @click="showInfo">
    <!-- 修饰符可以连续写 -->
    <a href="http://www.atguigu.com" @click.prevent.stop="showInfo">点我提示信息</a> 
</div>

4. 计算属性

插值方式

全名示例

<!DOCTYPE html> 
<html>
<head> 	
	<meta charset="UTF-8" /> 
	<title>姓名案例_插值语法实现</title> 	
	<!-- 引入Vue --> 	
	<script type="text/javascript" src="../js/vue.js"></script> 
</head> 
<body> 	
	<!-- 准备好一个容器-->  
	<div id="root"> 		
		姓:<input type="text" v-model:value="firstName"> <br/><br/> 	
		名:<input type="text" v-model:value="lastName"> <br/><br/>	
		全名:<span>{{firstName}}-{{lastName}}</span> 	
	</div> 
</body>  
	<script type="text/javascript"> 	
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 
		new Vue({ 		
			el:'#root', 		
			data:{ 			
				firstName:'张', 			
				lastName:'三' 		
			} 	
		}) 
	</script> 
</html>

提个需求,如firstName只要3位,其余位数不要,则代码如下:

<div id="root">			
	姓:<input type="text" v-model:value="firstName"> <br/><br/>		
	名:<input type="text" v-model:value="lastName"> <br/><br/>		
	全名:<span>{{firstName.slice(0,3)}}-{{lastName}}</span>		
</div>

但全名此部分过于复杂,可用methods实现。

1.methods方式
<!DOCTYPE html>
<html>
<head>	
	<meta charset="UTF-8" />	
	<title>姓名案例_methods实现</title>	
	<!-- 引入Vue -->	
	<script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
	<!-- 准备好一个容器-->
	<div id="root">
		姓:<input type="text" v-model="firstName"> <br/><br/>
		名:<input type="text" v-model="lastName"> <br/><br/>
		全名:<span>{{fullName()}}</span>
	</div>
</body>
<script type="text/javascript">
	Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
	new Vue({
		el:'#root',
		data:{
			firstName:'张',
			lastName:'三'
		},		
		methods: {
			fullName(){
				console.log('@---fullName')
				return this.firstName + '-' + this.lastName
			}	
		},	
	})
</script>
</html>
2.Computed方式
  • data中配置的键值对就是属性

  • 定义:要用的属性不存在,要通过已有属性计算得来。由姓和名计算出来全名,需要一个全新的配置项computed。

  • 原理:底层借助了Objcet.defineProperty方法提供的getter和setter

  • get函数什么时候执行?

  • (1).初次读取时会执行一次

  • (2).当依赖的数据发生改变时会被再次调用

  • 优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便

  • 备注:

  • 计算属性最终会出现在vm上,直接读取使用即可

  • 如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变

计算属性完整版写法

<!-- 准备好一个容器-->
<div id="root">
	姓:<input type="text" v-model="firstName">
	名:<input type="text" v-model="lastName">
	全名:<span>{{fullName}}</span>
</div>
<script>
	const vm = new Vue({
		el:'#root',
		data:{
			firstName:'张',
			lastName:'三',
		}
		computed:{
			fullName:{
				//get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
				//get什么时候调用?
				1.初次读取fullName时。
				2.所依赖的数据发生变化时。
				get(){ 
					console.log('get被调用了')
					return this.firstName + '-' + this.lastName
					},  
				//set什么时候调用? 当fullName被修改时。
				// 可以主动在控制台修改fullName来查看情况 
				set(value){
					console.log('set',value)
					const arr = value.split('-')           
					this.firstName = arr[0]            
					this.lastName = arr[1]          
				}            
			}        
		}    
	})
</script>

计算属性简写--只考虑读取计算属性值,不考虑设置计算属性值才可以用简写形式

<!-- 准备好一个容器-->
<div id="root">
	姓:<input type="text" v-model="firstName">
	名:<input type="text" v-model="lastName">
	全名:<span>{{fullName}}</span>
</div>
<script>
	const vm = new Vue({
		el:'#root',
		data:{
			firstName:'张',
			lastName:'三',
		}
		computed:{
			fullName() {
				console.log('get被调用了')
				return this.firstName + '-' + this.lastName
			}
		}
	})
</script>

注意:不能使用{{fullName()}}方式调用。在computed中的fullName()不是函数,是执行完这个函数后向vm这个实例上的fullName属性赋值。

5.watch监视属性

新建案例天气案例

<!-- 准备好一个容器-->
<div id="root">
    <h2>今天天气很{{info}}</h2>
    <!-- 绑定事件的时候:@xxx="yyy" yyy可以写一些简单的语句 -->
    <!-- <button @click="isHot = !isHot">切换天气</button> -->
    <button @click="changeWeather">切换天气</button>
</div>
<script type="text/javascript">
	Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
	const vm = new Vue({
		el:'#root', 
		data:{
			isHot:true,
		},
		computed:{
			info(){
				return this.isHot ? '炎热' : '凉爽' 
			} 
		}, 
		methods: {
			changeWeather(){
				this.isHot = !this.isHot
			}
		}
	})
</script>

如果需要监视isHot的改变,实现监视需要配置对象watch,

watch:{
	isHot:{
		immediate: true, // 初始化时让handler调用一下,先不写这行,handler演示后再写这行。
		// handler什么时候调用?当isHot发生改变时。
		handler(newValue, oldValue){
			console.log('isHot被修改了',newValue,oldValue)
		}
	}
} 

监视属性watch:

  • 当被监视的属性变化时, 回调函数自动调用, 进行相关操作

  • 监视的属性必须存在,才能进行监视。如计算属性也可监视,可将

watch:{
	info:{
		immediate: true, // 初始化时让handler调用一下
		// handler什么时候调用?当isHot发生改变时。
		handler(newValue, oldValue){
			console.log(' info被修改了',newValue,oldValue)
		}
	}
} 
<div id="app">
<!-- input中的v-model用于在表单控件元素创建双向数据绑定-->
   <input type="text" v-model="cityName">
<script>
       var vm = new Vue({
           el:'#app',
           data:{
               cityName:'shanghai'
           },
           // 使用watch监听cityName变化
           watch: {
               cityName(newName,oldName){
                   console.log(newName,oldName)
               }
           }
       })
</script>

●监视的两种写法:

  • (1).new Vue时传入watch配置

  • (2).通过vm.$watch监视

<!-- 准备好一个容器-->
<div id="root">
	<h2>今天天气很{{ info }}</h2>
	<button @click="changeWeather">切换天气</button>
</div>
<script>
	const vm = new Vue({
		el:'#root',
		data:{
			isHot:true,
		}, 
		computed:{
			info(){
				return this.isHot ? '炎热' : '凉爽'
			}
		},
		methods: {
			changeWeather(){
				this.isHot = !this.isHot
			}
		}, 
        //第一种写法
		watch:{
			isHot:{
				mmediate: true, // 初始化时让handler调用一下
				// handler什么时候调用?当isHot发生改变时。
				handler(newValue, oldValue){
					console.log('isHot被修改了',newValue,oldValue)
				}
			}
		}
	})
    //第二种写法(了解)
        vm.$watch('isHot',{
		immediate:true, //初始化时让handler调用一下
		//handler什么时候调用?当isHot发生改变时。
		handler(newValue,oldValue){
			console.log('isHot被修改了',newValue,oldValue)
		}
	})
</script>

深度监视:

  • (1).Vue中的watch默认不监测对象内部值的改变(一层)

  • (2).配置deep:true可以监测对象内部值改变(多层)

备注:

(1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以

(2).使用watch时根据数据的具体结构,决定是否采用深度监视

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>天气案例_深度监视</title> <!-- 引入Vue -->
    <script src="https://cdn.bootcss.com/vue/2.5.20/vue.min.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <h2>今天天气很{{info}}</h2> <button @click="changeWeather">切换天气</button><hr/>
        <h3>a的值是:{{numbers.a}}</h3> <button @click="numbers.a++">点我让a+1</button>
        <h3>b的值是:{{numbers.b}}</h3> <button @click="numbers.b++">点我让b+1</button> 
        <button @click="numbers = {a:666,b:888}">彻底替换掉numbers</button> {{numbers.c.d.e}}
    </div>
</body>
<script type="text/javascript">		
    Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。	
    const vm = new Vue({			
        el:'#root',			
        data:{				
            isHot:true,				
            numbers:{					
                a:1,					
                b:1,					
                c:{						
                    d:{							
                        e:100						
                    }					
                }				
            }			
        },			
        computed:{				
            info(){					
                return this.isHot ? '炎热' : '凉爽'				
            }			
        },			
        methods: {				
            changeWeather(){					
                this.isHot = !this.isHot				
            }			
        },			
        watch:{				
            isHot:{					
                // immediate:true, //初始化时让handler调用一下			
                //handler什么时候调用?当isHot发生改变时。			
                handler(newValue,oldValue){						
                    console.log('isHot被修改了',newValue,oldValue)		
                }				
            },				
            //监视多级结构中某个属性的变化				
            /* 'numbers.a':{					
                handler(){						
                    console.log('a被改变了')					
                }				
            } */				
            //监视多级结构中所有属性的变化				
            numbers:{					
                deep:true,					
                handler(){						
                    console.log('numbers改变了')					
                }				
            }			
        }		
    })	
</script>
</html>

监视属性简写

不需要immediate和deep时,就可以使用简写形式。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>天气案例_深度监视</title> <!-- 引入Vue -->
    <script src="https://cdn.bootcss.com/vue/2.5.20/vue.min.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <h2>今天天气很{{info}}</h2> <button @click="changeWeather">切换天气</button>
        <hr />
        <h3>a的值是:{{numbers.a}}</h3> <button @click="numbers.a++">点我让a+1</button>
        <h3>b的值是:{{numbers.b}}</h3> <button @click="numbers.b++">点我让b+1</button> <button
            @click="numbers = {a:666,b:888}">彻底替换掉numbers</button> {{numbers.c.d.e}}
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
    const vm = new Vue({
        el: '#root',
        data: {
            isHot: true,
            numbers: {
                a: 1,
                b: 1,
                c: {
                    d: {
                        e: 100
                    }
                }
            }
        },
        computed: {
            info() {
                return this.isHot ? '炎热' : '凉爽'
            }
        },
        methods: {
            changeWeather() {
                this.isHot = !this.isHot
            }
        },
        watch: {
            isHot: {
                // immediate:true, //初始化时让handler调用一下 					
                //handler什么时候调用?当isHot发生改变时。 					
                handler(newValue, oldValue) {
                    console.log('isHot被修改了', newValue, oldValue)
                }
            },
            //监视多级结构中某个属性的变化
            /* 'numbers.a':{
                handler(){
                    console.log('a被改变了')		
                }
            } */
            //监视多级结构中所有属性的变化
            numbers: {
                deep: true,
                handler() {
                    console.log('numbers改变了')
                }
            }
        }
    })  	
</script>
</html>

computed和watch之间的区别:

  • computed能完成的功能,watch都可以完成

  • watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作

两个重要的小原则:

  1. 所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象

  2. 所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,这样this的指向才是vm 或 组件实例对象。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>姓名案例_watch实现</title> <!-- 引入Vue -->
    <script src="https://cdn.bootcss.com/vue/2.5.20/vue.min.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root"> 
        姓:<input type="text" v-model="firstName">
        名:<input type="text" v-model="lastName">
        全名:<span>{{fullName}}</span> <br /><br />
    </div>
</body>
<script type="text/javascript"> 		
    Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。	
    const vm = new Vue({		
        el:'#root',
        data:{		
            firstName:'张',				
            lastName:'三',	
            fullName:'张-三'
        }, 			
        watch:{ 				
            firstName(val){ 					
                // setTimeout(()=>{  当姓改变后等1秒再有反馈 					
                    // 	console.log(this) 						
                    this.fullName = val + '-' + this.lastName 					
                    // },1000); 				
                }, 				
            lastName(val){ 					
                this.fullName = this.firstName + '-' + val
            } 			
            } 		
        }) 	
</script>
</html>

1. 过滤器(非重点)

定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。

语法:

  • 注册过滤器:Vue.filter(name,callback) 或 new Vue{filters:{}}

  • 使用过滤器:{{ xxx | 过滤器名}} 或 v-bind:属性 = "xxx | 过滤器名"

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>过滤器</title>
		<script type="text/javascript" src="../js/vue.js"></script>
		<script type="text/javascript" src="../js/dayjs.min.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>显示格式化后的时间</h2>
			<!-- 计算属性实现 -->
			<h3>现在是:{{fmtTime}}</h3>
			<!-- methods实现 -->
			<h3>现在是:{{getFmtTime()}}</h3>
			<!-- 过滤器实现 -->
			<h3>现在是:{{time | timeFormater}}</h3>
			<!-- 过滤器实现(传参) -->
			<h3>现在是:{{time | timeFormater('YYYY_MM_DD')}}</h3>
		</div>
	</body>
	<script type="text/javascript">
		Vue.config.productionTip = false
		//全局过滤器
		Vue.filter('mySlice',function(value){
			return value.slice(0,4)
		})
		new Vue({
			el:'#root',
			data:{
				time:1621561377603, //时间戳
				msg:'你好,尚硅谷'
			},
			computed: {
				fmtTime(){
					return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')
				}
			},
			methods: {
				getFmtTime(){
					return dayjs(this.time).format('YYYY年MM月DD日 HH:mm:ss')
				}
			},
			//局部过滤器
			filters:{
				timeFormater(value){
					return dayjs(value).format('YYYY年MM月DD日 HH:mm:ss')
				}
			},
			// //局部过滤器(传参),str='YYYY年MM月DD日 HH:mm:ss',''中为默认值,不传str时就用默认值
			// filters:{
			// 	timeFormater(value,str='YYYY年MM月DD日 HH:mm:ss'){
			// 		// console.log('@',value)
			// 		return dayjs(value).format(str)
			// 	}
			// }
		})
		new Vue({
			el:'#root2',
			data:{
				msg:'hello,atguigu!'
			}
		})
	</script>
</html>

备注:

  1. 过滤器也可以接收额外参数、多个过滤器也可以串联

  2. 并没有改变原本的数据, 是产生新的对应的数据

2.绑定样式

class样式

写法::class="xxx" xxx可以是字符串、对象、数。 所以分为三种写法,字符串写法,数组写法,对象写法 绑定样式:

  1. class样式 写法:class="xxx" xxx可以是字符串、对象、数组。 字符串写法适用于:类名不确定,要动态获取。 对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。 数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。

  2. style样式 :style="{fontSize: xxx}"其中xxx是动态值。 :style="[a,b]"其中a、b是样式对象。

字符串写法

字符串写法适用于:类名不确定,要动态获取。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>绑定样式</title>
		<style>
			.basic{
				width: 400px;
				height: 100px;
				border: 1px solid black;
			}
			
			.happy{
				border: 4px solid red;;
				background-color: rgba(255, 255, 0, 0.644);
				background: linear-gradient(30deg,yellow,pink,orange,yellow);
			}
		</style>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
			<div class="basic" :class="mood" @click="changeMood">{{name}}</div> <br/><br/>
		</div>
	</body>
	<script type="text/javascript">
		Vue.config.productionTip = false
		const vm = new Vue({
			el:'#root',
			data:{
				name:'尚硅谷',
				mood:'normal',
			},
			methods: {
				changeMood(){
					this.mood = 'happy'
				}
			},
		})
	</script>
</html>

数组写法

数组写法适用于:要绑定多个样式,个数不确定,名字也不确定。

<style>
    .atguigu1{
        background-color: yellowgreen;
    }
    .atguigu2{
        font-size: 30px;
        text-shadow:2px 2px 10px red;
    }
    .atguigu3{
        border-radius: 20px;
    }
</style>
<!-- 准备好一个容器-->
<div id="root">
    <!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
    <div class="basic" :class="classArr">{{name}}</div>
</div>
<script>
    const vm = new Vue({
        el:'#root',
        data:{
            classArr: ['atguigu1','atguigu2','atguigu3']
        }
    })
</script>

对象写法

对象写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。

<style>
    .atguigu1{
        background-color: yellowgreen;
    }
    .atguigu2{
        font-size: 30px;
        text-shadow:2px 2px 10px red;
    }
</style>
<!-- 准备好一个容器-->
<div id="root">
    <!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
	<div class="basic" :class="classObj">{{name}}</div>
</div>
<script>
	const vm = new Vue({
        el:'#root',
        data:{
            classObj:{
                atguigu1:false,
                atguigu2:false,
			}
        }
    })
</script>

style样式

有两种写法,对象写法,数组写法

对象写法

<!-- 准备好一个容器 -->
 <div id="root">
     <!--绑定style样式--对象写法 -->
     <div class="basic" :style="styleObj">{{name}}</div>
 </div>
 
 <script>
     const vm = new Vue({
         el:'#root',
         data:{
             styleObj:{
                 fontSize: '40px',
                 color:'red',
            }
         }
     })
 </script>

数组写法

<!--准备好一个容器-->
 <div id="root">
     <!--绑定style样式--数组写法 -->
     <div class="basic" :style="styleArr">{{name}}</div>
 </div>
 
 <script>
     const vm = new Vue({
         el:'#root',
         data:{
             styleArr:[
                 {
                     fontSize: '40px',
                     color:'blue',
                 },
                 {
                     backgroundColor:'gray'
                 }
             ]
         }
     })
 </script>

整体代码如下:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>绑定样式</title>
		<style>
			.basic{
				width: 400px;
				height: 100px;
				border: 1px solid black;
			}
			
			.happy{
				border: 4px solid red;;
				background-color: rgba(255, 255, 0, 0.644);
				background: linear-gradient(30deg,yellow,pink,orange,yellow);
			}
			.sad{
				border: 4px dashed rgb(38, 2, 197);
				background-color: gray;
			}
			.normal{
				background-color: skyblue;
			}

			.atguigu1{
				background-color: yellowgreen;
			}
			.atguigu2{
				font-size: 30px;
				text-shadow:2px 2px 10px red;
			}
			.atguigu3{
				border-radius: 20px;
			}
		</style>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
			<div class="basic" :class="mood" @click="changeMood">{{name}}</div> <br/><br/>

			<!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
			<div class="basic" :class="classArr">{{name}}</div> <br/><br/>

			<!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
			<div class="basic" :class="classObj">{{name}}</div> <br/><br/>

			<!-- 绑定style样式--对象写法 -->
			<div class="basic" :style="styleObj">{{name}}</div> <br/><br/>
			<!-- 绑定style样式--数组写法 -->
			<div class="basic" :style="styleArr">{{name}}</div>
		</div>
	</body>
	<script type="text/javascript">
		Vue.config.productionTip = false
		const vm = new Vue({
			el:'#root',
			data:{
				name:'hbpu.',
				mood:'normal',
				classArr:['atguigu1','atguigu2','atguigu3'],
				classObj:{
					atguigu1:false,
					atguigu2:false,
				},
				styleObj:{
					fontSize: '40px',
					color:'red',
				},
				styleObj2:{
					backgroundColor:'orange'
				},
				styleArr:[
					{
						fontSize: '40px',
						color:'blue',
					},
					{
						backgroundColor:'gray'
					}
				]
			},
			methods: {
				changeMood(){
					const arr = ['happy','sad','normal']
					const index = Math.floor(Math.random()*3)
					this.mood = arr[index]
				}
			},
		})
	</script>
</html>

3. 收集表单数据(v-model)

案例如下:

若:,则v-model收集的是value值,用户输入的就是value值。

<!-- 准备好一个容器-->
<div id="root">
    <form @submit.prevent="demo">
        账号:<input type="text" v-model="account"> 		 <br/><br/>
       	密码:<input type="password" v-model="password"> <br/><br/>
        <button>提交</button>
    </form>
</div>
<script type="text/javascript">
    Vue.config.productionTip = false
    new Vue({
        el:'#root',
        data:{
                account:'',
                password:'',
            }
        },
        methods: {
            demo(){
              return
            }
        }
    })
</script>

若:,则v-mdel收集的是value值,且要给标签配置value值。

<!--准备好一个容器-->
 <div id="root">
     <form @submit.prevent="demo">
         性别:
         男<input type="radio" name="sex" v-model="sex" value="male">
         女<input type="radio" name="sex" v-model="sex" value="female">
     </form>
 </div>
 
 <script type="text/javascript">
     Vue.config.productionTip = false
     new Vue({
         el:'#root',
         data:{      
                 sex:'female'
             }
         },
         methods: {
             demo(){
                 return
             }
         }
     })
 </script>

若:

  1. 没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)

  2. 配置input的value属性:

    • v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)

    • v-model的初始值是数组,那么收集的的就是value组成的数组

<!-- 准备好一个容器-->
<div id="root">
    <form @submit.prevent="demo">
        爱好:
        学习<input type="checkbox" v-model="hobby" value="study">
        打游戏<input type="checkbox" v-model="hobby" value="game">
        吃饭<input type="checkbox" v-model="hobby" value="eat">
        <br/><br/>
        所属校区
        <select v-model="userInfo.city">
            <option value="">请选择校区</option>
            <option value="beijing">北京</option>
            <option value="shanghai">上海</option>
            <option value="shenzhen">深圳</option>
            <option value="wuhan">武汉</option>
        </select>
        <br/><br/>
        其他信息:
        <textarea v-model="other"></textarea> <br/><br/>
        <input type="checkbox" v-model="agree">阅读并接受
        <a href="http://www.baidu.com">《用户协议》</a>
        <button>提交</button>
    </form>
</div>
<script type="text/javascript">
    Vue.config.productionTip = false
    new Vue({
        el:'#root',
        data:{
          
                hobby:[],
                city:'beijing',
                other:'',
                agree:''
        },
        methods: {
            demo(){
                return
            }
        }
    })
</script>

备注:v-model的三个修饰符:

  • lazy:失去焦点再收集数据

  • number:输入字符串转为有效的数字

  • trim:输入首尾空格过滤

可加入年龄一行,加入三个修饰符后完整代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>收集表单数据</title>
    <script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <form @submit.prevent="demo">
            账号:<input type="text"v-model.trim="account"> <br/><br/>
            密码:<input type="password"v-model.trim="password"> <br/>
            年龄:<input type="number"v-model.number="age"> <br/><br/>
            性别:  <!--要绑定value值,否则取不到具体值 -->
            男<input type="radio" name="sex" v-model="sex" value="male">
            女<input type="radio" name="sex" v-model="sex" value="female"> <br/><br/>
            爱好:
            学习<input type="checkbox"v-model="hobby" value="study">
            打游戏<input type="checkbox" v-model="hobby" value="game">
            吃饭<input type="checkbox" v-model="hobby" value="food">  
            <br/><br/>
            所属校区
            <select v-model="city">
                <option value="">请选择校区</option>
                <option value="beijing">北京</option>
                <option value="shanghai">上海</option>
                <option value="shenzhen">深圳</option>
                <option value="wuhan">武汉</option>
            </select>
            <br/><br/>
            其他信息:
            <textarea v-model.lazy="other"></textarea> <br/><br/>
            <input type="checkbox"  v-model="agree">阅读并接受
            <a href="http://www.baidu.com">《用户协议》</a>
            <button>提交</button>
        </form>
    </div>
</body>   
<script type="text/javascript">
     Vue.config.productionTip = false
     new Vue({
           el:'#root',
           data:{
           		 account:'',
                  password:'',
                  age:'',
                  sex:'male',
                  hobby:[],
                  city:'beijing',
                  other:'',
                  agree:''
           },
           methods: {
              demo(){
                  return
              }
           },
       })
    </script>
</html>

4. 内置指令

1 .v-text指令:(使用的比较少)

  1. 作用:向其所在的节点中渲染文本内容。

  2. 与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。

<!-- 准备好一个容器-->
<div id="root">
    <div>你好,{{name}}</div>
    <div v-text="name"></div>
    <div v-text="str"></div>
</div>
<script type="text/javascript">
    Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
     new Vue({
        el:'#root',
        data:{
            name:'张三',
            str:'<h3>你好啊!</h3>'
        }
    })
</script>

2 .v-html指令:(使用的很少)

  1. 作用:向指定节点中渲染包含html结构的内容。

  2. 与插值语法的区别:

  • v-html会替换掉节点中所有的内容,{{xx}}则不会。

  • v-html可以识别html结构。

3.严重注意:v-html有安全性问题!!!!

  • 在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。

  • 一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!

<!-- 准备好一个容器-->
<div id="root">
    <div>你好,{{name}}</div>
    <div v-html="str"></div>
</div>
<script type="text/javascript">
    Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
    new Vue({
        el:'#root',
        data:{
            name:'张三',
            str:'<h3>你好啊!</h3>',
        }
    })
</script>

3. v-bind指令(没有值):

实现单向数据绑定

<div id="app">
    <input v-bind:value="msg">
</div>  
<script>
    var vm = new Vue({
        el: '#app',
        data: {
            msg: '我是v-bind'
        }
    })
</script>

使用v-bind:value,则使得value后的msg作为js表达式,而不是字符串。

4 .v-on

5 .v-for

  • 用于展示列表数据

  • 语法:v-for="(item, index) in xxx" :key="yyy"

  • 可遍历:数组、对象、字符串(用的很少)、指定次数(用的很少)

<div id="root">
    <!-- 遍历数组-->
    <h2>人员列表(遍历数组)</h2>
    <ul>
        <li v-for="(p,index) of persons" :key="index">
            {{p.name}}-{{p.age}}
        </li>
    </ul>
    <!-- 遍历对象,k是对象中的key,value是对象中的值-->
      <h2>汽车信息(遍历对象)</h2>
    <ul>
        <li v-for="(value,k) of car" :key="k">
            {{k}}-{{value}}
        </li>
    </ul>
      <!-- 遍历字符串-->
    <h2>测试遍历字符串(用得少)</h2>
    <ul>
        <li v-for="(char,index) of str" :key="index">
            {{char}}-{{index}}
        </li>
    </ul>
       <!-- 遍历指定次数-->
     <h2>测试遍历指定次数(用得少)</h2>
    <ul>
        <li v-for="(number,index) of 5" :key="index">
            {{index}}-{{number}}
        </li>
    </ul>
</div>
<script>
    const vm = new Vue({
        el:'#root',
        data: {
           persons: [
              { id: '001', name: '张三', age: 18 },
              { id: '002', name: '李四', age: 19 },
              { id: '003', name: '王五', age: 20 }
           ],
           car: {
              name: '奥迪A8',
              price: '70万',
              color: '黑色'
           },
           str: 'hello'
       }
    })
</script>

1.条件渲染

v-if

  • (1).v-if="表达式"

  • (2).v-else-if="表达式"

  • (3).v-else="表达式"

  • 适用于:切换频率较低的场景

  • 特点:不展示的DOM元素直接被移除

  • 注意:v-if可以和:v-else-if、v-else一起使用,但要求结构不能被“打断”

<!-- 准备好一个容器-->
<div id="root">
    <!-- 使用v-if做条件渲染 -->
    <h2 v-if="false">欢迎来到{{name}}</h2>
    <h2 v-if="1 === 1">欢迎来到{{name}}</h2>
    <!-- v-else和v-else-if -->
    <div v-if="n === 1">Angular</div>
    <div v-else-if="n === 2">React</div>
    <div v-else-if="n === 3">Vue</div>
    <div v-else>哈哈</div>
    <!-- v-if与template的配合使用 -->
    <!-- 就不需要写好多个判断,写一个就行 -->
    <!-- 这里的思想就像事件代理的使用 -->
    <template v-if="n === 1">
        <h2>你好</h2>
        <h2>尚硅谷</h2>
        <h2>北京</h2>
    </template>
</div>
<script type="text/javascript">
		Vue.config.productionTip = false
		const vm = new Vue({
			el:'#root',
			data:{
				name:'尚硅谷',
				n:0
			}
		})
</script>

v-show

  • undefined 写法:v-show="表达式"

  • undefined 适用于:切换频率较高的场景

  • undefined 特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉(display:none)

备注:使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到

v-if 是实打实地改变dom元素,v-show 是隐藏或显示dom元素

<!-- 准备好一个容器-->
<div id="root">
    <!-- 使用v-show做条件渲染 -->
    <h2 v-show="false">欢迎来到{{name}}</h2>
    <h2 v-show="1 === 1">欢迎来到{{name}}</h2>
</div>

2.学生列表案例

示例图如下:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <script src="vue.js"></script>
</head>
<body>
  <div id="app">
    <button @click="add">添加学生</button>
    <button @click="del">删除学生</button>
    <table border="1" width="50%" style="border-collapse: collapse">
      <tr>
        <th>班级</th>
        <th>姓名</th>
        <th>性别</th>
        <th>年龄</th>
      </tr>
      <tr align="center" v-for="item in students">
        <td>{{item.grade}}</td>
        <td>{{item.name}}</td>
        <td>{{item.gender}}</td>
        <td>{{item.age}}</td>
      </tr>
    </table>
  </div>
  <script>
    var vm = new Vue({
      el: '#app',
      data: {
        students: []
      },
      methods: {
        // 添加学生信息
        add () {
          var student = {grade: '1', name: '张三', gender: '男', age: 25}
          this.students.push(student)
        },
        // 删除学生信息
        del () {
          this.students.pop()
        }
      }
    })
  </script>
</body>
</html>

3. 生命周期

简介生命周期

Vue 实例有⼀个完整的⽣命周期,也就是从new Vue()、初始化事件(.once事件)和生命周期、编译模版、挂载Dom -> 渲染、更新 -> 渲染、卸载 等⼀系列过程,称这是Vue的⽣命周期。

先来一张尚硅谷的图:

  1. beforeCreate(创建前):数据监测(getter和setter)和初始化事件还未开始,此时 data 的响应式追踪、event/watcher 都还没有被设置,也就是说不能访问到data、computed、watch、methods上的方法和数据。

  2. created(创建后):实例创建完成,实例上配置的 options 包括 data、computed、watch、methods 等都配置完成,但是此时渲染得节点还未挂载到 DOM,所以不能访问到 $el属性。

  3. beforeMount(挂载前):在挂载开始之前被调用,相关的render函数首次被调用。此阶段Vue开始解析模板,生成虚拟DOM存在内存中,还没有把虚拟DOM转换成真实DOM,插入页面中。所以网页不能显示解析好的内容。

  4. mounted(挂载后):在el被新创建的 vm.$el(就是真实DOM的拷贝)替换,并挂载到实例上去之后调用(将内存中的虚拟DOM转为真实DOM,真实DOM插入页面)。此时页面中呈现的是经过Vue编译的DOM,这时在这个钩子函数中对DOM的操作可以有效,但要尽量避免。一般在这个阶段进行:开启定时器,发送网络请求,订阅消息,绑定自定义事件等等

  5. beforeUpdate(更新前):响应式数据更新时调用,此时虽然响应式数据更新了,但是对应的真实 DOM 还没有被渲染(数据是新的,但页面是旧的,页面和数据没保持同步呢)。

  6. updated(更新后) :在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。此时 DOM 已经根据响应式数据的变化更新了。调用时,组件 DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。

  7. beforeDestroy(销毁前):实例销毁之前调用。这一步,实例仍然完全可用,this 仍能获取到实例。在这个阶段一般进行关闭定时器,取消订阅消息,解绑自定义事件。

  8. destroyed(销毁后):实例销毁后调用,调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务端渲染期间不被调用。

引出生命周期:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>引出生命周期</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 
				生命周期:
						1.又名:生命周期回调函数、生命周期函数、生命周期钩子。
						2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。
						3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。
						4.生命周期函数中的this指向是vm 或 组件实例对象。
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<h2 v-if="a">你好啊</h2>
			<h2 :style="{opacity}">欢迎学习Vue</h2>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		 new Vue({
			el:'#root',
			data:{
				a:false,
				opacity:1
			},
			methods: {
				
			},
	//Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
			mounted(){
				console.log('mounted',this)
				setInterval(() => {
					this.opacity -= 0.01
					if(this.opacity <= 0) this.opacity = 1
				},16)
			},
		})
		//通过外部的定时器实现(不推荐)
		/* setInterval(() => {
			vm.opacity -= 0.01
			if(vm.opacity <= 0) vm.opacity = 1
		},16) */
	</script>
</html>

mounted()钩子函数的运行时机,Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted。

各个生命周期展示

1.beforeCreate(创建前)

数据监测(getter和setter)和初始化事件还未开始,此时 data 的响应式追踪、event/watcher 都还没有被设置,也就是说不能访问到data、computed、watch、methods上的方法和数据。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>分析生命周期</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root" :x="n">
			<h2 v-text="n"></h2>
			<h2>当前的n值是:{{n}}</h2>
			<button @click="add">点我n+1</button>
			
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

		new Vue({
			el:'#root',
			data:{
				n:1
			},
			methods: {
				add(){
					console.log('add')
					this.n++
				}
			},
			beforeCreate() {  // 第1步验证
				console.log('beforeCreate')
				console.log(this)
				debugger   //调试命令
			}
		})
	</script>
</html>

这里没有n,也没有add()函数。

2.created(创建后)

实例创建完成,实例上配置的 options 包括 data、computed、watch、methods 等都配置完成,但是此时渲染得节点还未挂载到 DOM,所以不能访问到 $el属性。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>分析生命周期</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root" :x="n">
			<h2 v-text="n"></h2>
			<h2>当前的n值是:{{n}}</h2>
			<button @click="add">点我n+1</button>
		</div>
	</body>
	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		new Vue({
			el:'#root',
			data:{
				n:1
			},
			methods: {
				add(){
					console.log('add')
					this.n++
				}
			},
			beforeCreate() {  // 第1步验证
				console.log('beforeCreate')
			},
			created() {
				console.log('Created')
				console.log(this)
				debugger   //调试命令
			},
		})
	</script>
</html>

来讲一下图中间大框框的内容

先判断有没有 el 这个配置项,没有就调用 vm.$mount(el),如果两个都没有就一直卡着,显示的界面就是最原始的容器的界面。有 el 这个配置项,就进行判断有没有 template 这个配置项,没有 template 就将 el 绑定的容器编译为 vue 模板,来个对比图。

3.beforeMount(挂载前)

在挂载开始之前被调用,相关的render函数首次被调用。此阶段Vue开始解析模板,生成虚拟DOM存在内存中,还没有把虚拟DOM转换成真实DOM,插入页面中。所以网页不能显示解析好的内容。

<body>
    <!-- 准备好一个容器-->
    <div id="root" :x="n">
        <h2>当前的n值是:{{n}}</h2>
        <button @click="add">点我n+1</button>		
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

    new Vue({
        el:'#root',
        data:{
            n:1
        },
        methods: {
            add(){
                console.log('add')
                this.n++
            }
        },
        beforeCreate() {  // 第1步验证
            console.log('beforeCreate')
        },
        created() {
            console.log('Created')
        },
        beforeMount() {
            console.log('beforeMount')
            console.log(this)
            debugger   //调试命令
        },
    })
</script>

Vue已经完成解析,但没向页面挂载显示。

4.mounted(挂载后)

在el被新创建的 vm.$el(就是真实DOM的拷贝)替换,并挂载到实例上去之后调用(将内存中的虚拟DOM转为真实DOM,真实DOM插入页面)。此时页面中呈现的是经过Vue编译的DOM,这时在这个钩子函数中对DOM的操作可以有效,但要尽量避免。一般在这个阶段进行:开启定时器,发送网络请求,订阅消息,绑定自定义事件等等。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>分析生命周期</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root" :x="n">
			<h2>当前的n值是:{{n}}</h2>
			<button @click="add">点我n+1</button>		
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

		new Vue({
			el:'#root',
			data:{
				n:1
			},
			methods: {
				add(){
					console.log('add')
					this.n++
				}
			},
			beforeCreate() {  // 第1步验证
				console.log('beforeCreate')
			},
			created() {
				console.log('Created')
			},
			beforeMount() {
				console.log('beforeMount')
			},
			mounted() {
				console.log('mounted')
				console.log(this)
				debugger   //调试命令
			},
		})
	</script>
</html>

5.beforeUpdate(更新前)

响应式数据更新时调用,此时虽然响应式数据更新了,但是对应的真实 DOM 还没有被渲染(数据是新的,但页面是旧的,页面和数据没保持同步呢)。

<body>
		<!-- 准备好一个容器-->
		<div id="root" :x="n">
			<h2>当前的n值是:{{n}}</h2>
			<button @click="add">点我n+1</button>		
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

		new Vue({
			el:'#root',
			data:{
				n:1
			},
			methods: {
				add(){
					console.log('add')
					this.n++
				}
			},
			beforeCreate() {  // 第1步验证
				console.log('beforeCreate')
			},
			created() {
				console.log('Created')
			},
			beforeMount() {
				console.log('beforeMount')
			},
			mounted() {
				console.log('mounted')
			},
			beforeUpdate() {
				console.log('beforeUpdate')
				console.log(this.n)
				debugger   //调试命令
			},
		})
	</script>

需要点击button后,才会有以下效果。

此时要注意控制台上的n是2,页面上的n还是1。

6.updated(更新后)

在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。此时 DOM 已经根据响应式数据的变化更新了。调用时,组件 DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。

updated() {
    console.log('updated')
    console.log(this.n)
    debugger   //调试命令
},

此时页面显示和data中的数据统一。

7.beforeDestroy(销毁前)

实例销毁之前调用。这一步,实例仍然完全可用,this 仍能获取到实例。在这个阶段一般进行关闭定时器,取消订阅消息,解绑自定义事件。

<body>
    <!-- 准备好一个容器-->
    <div id="root" :x="n">
        <h2>当前的n值是:{{n}}</h2>
        <button @click="add">点我n+1</button>	
        <button @click="bye">点我销毁vm</button>	
        <!-- 新增button事件-->
    </div>
</body>
<script type="text/javascript">
    Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
    new Vue({
        el:'#root',
        data:{
            n:1
        },
        methods: {
            add(){
                console.log('add')
                this.n++
            },
            bye(){
                console.log('bye')
                this.$destroy()
            }
        },
        beforeCreate() {  // 第1步验证
            console.log('beforeCreate')
        },
        created() {
            console.log('Created')
        },
        beforeMount() {
            console.log('beforeMount')
        },
        mounted() {
            console.log('mounted')
        },
        beforeUpdate() {
            console.log('beforeUpdate')
        },
        updated() {
            console.log('updated')
        },
        beforeDestroy() {
            console.log('beforeDestroy')
        },
    })
</script>

可演示点击add按钮后再点击销毁按钮。

此时调用了bye方法和beforeDestroy钩子函数。

8.destroyed(销毁后)

实例销毁后调用,调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务端渲染期间不被调用。

destroyed() {
	console.log('destroyed')
},

点击销毁后会被调用。

4.非单文件组件

  • 组件定义:实现应用中局部功能代码和资源的集合。包括结构、交互和样式。

  • 非单文件组件:一个文件中包含有n个组件。文件为html文件。

  • 单文件组件:一个文件中包含有一个组件。文件为vue文件。

新建html文件

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>基本使用</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2>学校名称:{{schoolName}}</h2>
			<h2>学校地址:{{address}}</h2>
			<hr>
			<h2>学生名称:{{studentName}}</h2>
			<h2>学生年龄:{{age}}</h2>
		</div>
	</body>
	<script type="text/javascript">
		Vue.config.productionTip = false
		new Vue({
			el:'#root',
			data:{
				schoolName:'湖北理工',
				address:'湖北黄石',
				studentName:'张三',
				age:18
			}
		})
	</script>
</html>

现在要用组件的形式来写。从创建组件开始。

基本使用

Vue中使用组件的三大步骤:

  1. 定义组件(创建组件)

  2. 注册组件

  3. 使用组件(写组件标签)

定义组件

使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别;

区别如下:

  1. undefined el不要写,为什么? ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。

  2. undefined data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。

如何注册组件?

1.局部注册:靠new Vue的时候传入components选项 ​ 2.全局注册:靠Vue.component('组件名',组件)

编写组件标签:

<school></school>

讲解一下面试小问题:data必须写成函数:

这是 js 底层设计的原因:举个例子

对象形式

let data = {
    a: 99,
    b: 100
}
let x = data;
let y = data;
// x 和 y 引用的都是同一个对象,修改 x 的值, y 的值也会改变
x.a = 66;
console.loh(x); // a:66 b:100
console.log(y); // a:66 b:100

函数形式

function data() {
    return {
        a: 99,
        b: 100
    }
}
let x = data();
let y = data();
console.log(x === y); // false
// 我的理解是函数每调用一次就创建一个新的对象返回给他们

备注:使用template可以配置组件结构。

创建一个组件案例:Vue.extend() 创建或者直接创建对象

<script type="text/javascript"> 
    Vue.config.productionTip = false 
    //第一步:创建school组件也直接定义为一个Object 
    // const school = {....} 
    //第一步:创建school组件 
    const school = Vue.extend({ 
        template:` 
				<div class="demo"> 
					<h2>学校名称:{{schoolName}}</h2> 
					<h2>学校地址:{{address}}</h2> 
					<button @click="showName">点我提示学校名</button>	 
    			</div> 
			`, 
        // el:'#root', //组件定义时,一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器。 
        data(){ 
            return { 
                schoolName:'尚硅谷', 
                address:'北京昌平' 
            } 
        }, 
        methods: { 
            showName(){ 
                alert(this.schoolName) 
            } 
        }, 
    }) 
    //第一步:创建student组件 
    const student = Vue.extend({ 
        template:` 
				<div> 
					<h2>学生姓名:{{studentName}}</h2> 
					<h2>学生年龄:{{age}}</h2> 
    			</div> 
			`, 
        data(){ 
            return { 
                studentName:'张三', 
                age:18 
            } 
        } 
    }) 
    //第一步:创建hello组件 
    const hello = Vue.extend({ 
        template:` 
				<div>	 
					<h2>你好啊!{{name}}</h2> 
    			</div> 
			`, 
        data(){ 
            return { 
                name:'Tom' 
            } 
        } 
    }) 
</script>

注册组件

  • 局部注册:靠new Vue的时候传入components选项

  • 全局注册:靠Vue.component('组件名',组件)

局部注册

<script>
	//创建vm
    new Vue({
        el: '#root',
        data: {
            msg:'你好啊!'
        },
        //第二步:注册组件(局部注册)
        components: {
            school: school,
            student: student
            // ES6简写形式
            // school,
            // student
        }
    })
</script>

全局注册

<script>
	//第二步:全局注册组件
	Vue.component('hello', hello)
</script>

写组件标签

<!-- 准备好一个容器-->
<div id="root">
    <hello></hello>
    <hr>
    <h1>{{msg}}</h1>
    <hr>
    <!-- 第三步:编写组件标签 -->
    <school></school>
    <hr>
    <!-- 第三步:编写组件标签 -->
    <student></student>
</div>

对于全局组件,可再生成一个新的div#root2。因hello是全局注册的组件,因此可以在所有的vue实例中直接应用。

<div id="root2">
			<hello></hello>
		</div>
 <!-- 生成一个新vue实例 -->
new Vue({
		el:'#root2',
	})

几个注意点:

关于组件名:

一个单词组成:

  • 第一种写法(首字母小写):school

  • 第二种写法(首字母大写):School

多个单词组成:

  • 第一种写法(kebab-case命名):my-school

  • 第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)

备注:

  1. (1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。

  2. (2).可以使用name配置项指定组件在开发者工具中呈现的名字。

关于组件标签:

  • 第一种写法:

  • 第二种写法:

备注:不用使用脚手架时,会导致后续组件不能渲染。

一个简写方式:

const school = Vue.extend(options) 可简写为:const school = options

组件的嵌套

比较简单,直接展示代码:

<!-- 准备好一个容器--> 
<div id="root"> 
    
</div> 
<script type="text/javascript"> 
    Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。 
    //定义student组件 
    const student = Vue.extend({ 
        name:'student', 
        template:` 
				<div> 
					<h2>学生姓名:{{name}}</h2>	 
					<h2>学生年龄:{{age}}</h2>	 
    			</div> 
			`, 
        data(){ 
            return { 
                name:'尚硅谷', 
                age:18 
            } 
        } 
    }) 
    //定义school组件 
    const school = Vue.extend({ 
        name:'school', 
        template:` 
				<div> 
					<h2>学校名称:{{name}}</h2>	 
					<h2>学校地址:{{address}}</h2>	 
					<student></student> 
    			</div> 
			`, 
        data(){ 
            return { 
                name:'尚硅谷', 
                address:'北京' 
            } 
        }, 
        // 注册组件(局部) 
        components:{ 
            student 
        } 
    }) 
    //定义hello组件 
    const hello = Vue.extend({ 
        template:`<h1>{{msg}}</h1>`, 
        data(){ 
            return { 
                msg:'欢迎来到尚硅谷学习!' 
            } 
        } 
    }) 
    //定义app组件 
    const app = Vue.extend({ 
        template:` 
				<div>	 
					<hello></hello> 
					<school></school> 
    			</div> 
			`, 
        components:{ 
            school, 
            hello 
        } 
    }) 
    //创建vm 
    new Vue({ 
        template:'<app></app>', 
        el:'#root', 
        //注册组件(局部) 
        components:{app} 
    }) 
</script>

VueComponent

  • school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。

  • 我们只需要写或,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)。

  • 特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!(这个VueComponent可不是实例对象)

  • 关于this指向:

    • 组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。

    • new Vue(options)配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。

  • VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。Vue的实例对象,以后简称vm。

Vue 在哪管理 VueComponent

一个重要的内置关系

  • 一个重要的内置关系:VueComponent.prototype.proto === Vue.prototype

  • 为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。

1.21 单文件组件

单文件组件就是将一个组件的代码写在 .vue 这种格式的文件中,webpack 会将 .vue 文件解析成 html,css,js这些形式。

来做个单文件组件的案例:

School.vue

<template>
	<div class="demo">
		<h2>学校名称:{{name}}</h2>
		<h2>学校地址:{{address}}</h2>
		<button @click="showName">点我提示学校名</button>	
	</div>
</template>

<script>
	 export default {
		name:'School',
		data(){
			return {
				name:'尚硅谷',
				address:'北京昌平'
			}
		},
		methods: {
			showName(){
				alert(this.name)
			}
		},
	}
</script>

<style>
	.demo{
		background-color: orange;
	}
</style>

App.vue

用来汇总所有的组件(大总管)

<template>
	<div>
		<h2>学生姓名:{{name}}</h2>
		<h2>学生年龄:{{age}}</h2>
	</div>
</template>

<script>
	 export default {
		name:'Student',
		data(){
			return {
				name:'张三',
				age:18
			}
		}
	}
</script>

main.js

在这个文件里面创建 vue 实例

import App from './App.vue'
new Vue({
	el:'#root',
	template:`<App></App>`,
	components:{App},
})

index.html

在这写 vue 要绑定的容器

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>练习一下单文件组件的语法</title>
	</head>
	<body>
		<!-- 准备一个容器 -->
		<div id="root"></div>
        <script type="text/javascript" src="../js/vue.js"></script>
		<script type="text/javascript" src="./main.js"></script>
	</body>
</html>

6.Vuex

原理图:

6.1 概念

在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。

6.2 何时使用?

多个组件需要共享数据时

6.3 搭建vuex环境

  1. 安装vuex3版本

    npm i vuex@3
    
  2. 创建文件:src/store/index.js

    //引入Vue核心库
    import Vue from 'vue'
    //引入Vuex
    import Vuex from 'vuex'
    //应用Vuex插件
    Vue.use(Vuex)
    
    //准备actions对象——响应组件中用户的动作
    const actions = {}
    //准备mutations对象——修改state中的数据
    const mutations = {}
    //准备state对象——保存具体的数据
    const state = {}
    
    //创建并暴露store
    export default new Vuex.Store({
    	actions,
    	mutations,
    	state
    })
    
  3. main.js中创建vm时传入store配置项

    //引入Vue
    import Vue from 'vue'
    //引入App
    import App from './App.vue'
    
    //引入store
    import store from './store'
    
    //关闭Vue的生产提示
    Vue.config.productionTip = false
    //创建vm
    
      new Vue({
    
      	el:'#app',
    
      	render: h => h(App),
    
      	store,	
    
      })
    

App.vue

<template>
	<div>
		
	</div>
</template>

<script>
	export default {
		name:'App',
	}
</script>

6.4 基本使用##

  1. 初始化数据、配置actions、配置mutations,操作文件store.js

      //引入Vue核心库
    
       import Vue from 'vue'
    
       //引入Vuex
    
       import Vuex from 'vuex'
    
       //引用Vuex
    
       Vue.use(Vuex)
    
       const actions = {
    
           //响应组件中加的动作
    
       	jia(context,value){
    
       		// console.log('actions中的jia被调用了',miniStore,value)
    
       		context.commit('JIA',value)
    
       	},
    
       }
    
       const mutations = {
    
           //执行加
    
       	JIA(state,value){
    
       		// console.log('mutations中的JIA被调用了',state,value)
    
       		state.sum += value
    
       	}
    
       }
    
       //初始化数据
    
       const state = {
    
          sum:0
    
       }
    
       //创建并暴露store
    
       export default new Vuex.Store({
    
       	actions,
    
       	mutations,
    
       	state,
    
       })
    
    

  1. 组件中读取vuex中的数据:$store.state.sum

  2. 组件中修改vuex中的数据:$store.dispatch('action中的方法名',数据)$store.commit('mutations中的方法名',数据)

    备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写commit

具体案例:

1.不越过dispatch操作

App.vue

<template>
	<div>
		<Count/>
	</div>
</template>

<script>
	import Count from './components/Count'
	export default {
		name:'App',
		components:{Count},
		mounted() {
			// console.log('App',this)
		},
	}
</script>

store/index.js

//该文件用于创建Vuex中最为核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)

//准备actions——用于响应组件中的动作
const actions = {
	jia(context,value){
		console.log('actions中的jia被调用了')
		context.commit('JIA',value)
	},
	jian(context,value){
		console.log('actions中的jian被调用了')
		context.commit('JIAN',value)
	}, 
	jiaOdd(context,value){
		console.log('actions中的jiaOdd被调用了')
		if(context.state.sum % 2){
			context.commit('JIA',value)
		}
	},
	jiaWait(context,value){
		console.log('actions中的jiaWait被调用了')
		setTimeout(()=>{
			context.commit('JIA',value)
		},500)
	}
}
//准备mutations——用于操作数据(state)
const mutations = {
	JIA(state,value){
		console.log('mutations中的JIA被调用了')
		state.sum += value
	},
	JIAN(state,value){
		console.log('mutations中的JIAN被调用了')
		state.sum -= value
	}
}
//准备state——用于存储数据
const state = {
	sum:0 //当前的和
}

//创建并暴露store
export default new Vuex.Store({
	actions,
	mutations,
	state,
})

Count.vue

<template>
	<div>
		<h1>当前求和为:{{$store.state.sum}}</h1>
		<select v-model.number="n">
			<option value="1">1</option>
			<option value="2">2</option>
			<option value="3">3</option>
		</select>
		<button @click="increment">+</button>
		<button @click="decrement">-</button>
		<button @click="incrementOdd">当前求和为奇数再加</button>
		<button @click="incrementWait">等一等再加</button>
	</div>
</template>

<script>
	export default {
		name:'Count',
		data() {
			return {
				n:1, //用户选择的数字
			}
		},
		methods: {
			increment(){
				this.$store.dispatch('jia',this.n)
			},
			decrement(){
				this.$store.dispatch('jian',this.n)
			},
			incrementOdd(){
				this.$store.dispatch('jiaOdd',this.n)
			},
			incrementWait(){
				this.$store.dispatch('jiaWait',this.n)
			},
		},
		mounted() {
			console.log('Count',this)
		},
	}
</script>

<style lang="css">
	button{
		margin-left: 5px;
	}
</style>

其他部分无变化。

由于actions中的jia和jian,没有做任何逻辑业务。因此可去掉,直接调用mutations中的JIA和JIAN。注意,此时要用commit,而不是dispatch。

去除jia和jian的index.js

//该文件用于创建Vuex中最为核心的store
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)

//准备actions——用于响应组件中的动作
const actions = {
	jiaOdd(context,value){
		console.log('actions中的jiaOdd被调用了')
		if(context.state.sum % 2){
			context.commit('JIA',value)
		}
	},
	jiaWait(context,value){
		console.log('actions中的jiaWait被调用了')
		setTimeout(()=>{
			context.commit('JIA',value)
		},500)
	}
}
//准备mutations——用于操作数据(state)
const mutations = {
	JIA(state,value){
		console.log('mutations中的JIA被调用了')
		state.sum += value
	},
	JIAN(state,value){
		console.log('mutations中的JIAN被调用了')
		state.sum -= value
	}
}
//准备state——用于存储数据
const state = {
	sum:0 //当前的和
}

//创建并暴露store
export default new Vuex.Store({
	actions,
	mutations,
	state,
})

Count.vue

<template>
	<div>
		<h1>当前求和为:{{$store.state.sum}}</h1>
		<select v-model.number="n">
			<option value="1">1</option>
			<option value="2">2</option>
			<option value="3">3</option>
		</select>
		<button @click="increment">+</button>
		<button @click="decrement">-</button>
		<button @click="incrementOdd">当前求和为奇数再加</button>
		<button @click="incrementWait">等一等再加</button>
	</div>
</template>

<script>
	export default {
		name:'Count',
		data() {
			return {
				n:1, //用户选择的数字
			}
		},
		methods: {
			increment(){
				this.$store.commit('JIA',this.n)
			},
			decrement(){
				this.$store.commit('JIAN',this.n)
			},
			incrementOdd(){
				this.$store.dispatch('jiaOdd',this.n)
			},
			incrementWait(){
				this.$store.dispatch('jiaWait',this.n)
			},
		},
		mounted() {
			console.log('Count',this)
		},
	}
</script>

<style lang="css">
	button{
		margin-left: 5px;
	}
</style>

6.5 getters的使用

  1. 概念:当state中的数据需要经过加工后再使用时,可以使用getters加工。不是必须的配置项

  2. store/index.js中追加getters配置

    //该文件用于创建Vuex中最为核心的store
    import Vue from 'vue'
    //引入Vuex
    import Vuex from 'vuex'
    //应用Vuex插件
    Vue.use(Vuex)
    
    //准备actions——用于响应组件中的动作
    const actions = {
    	/* jia(context,value){
    		console.log('actions中的jia被调用了')
    		context.commit('JIA',value)
    	},
    	jian(context,value){
    		console.log('actions中的jian被调用了')
    		context.commit('JIAN',value)
    	}, */
    	jiaOdd(context,value){
    		console.log('actions中的jiaOdd被调用了')
    		if(context.state.sum % 2){
    			context.commit('JIA',value)
    		}
    	},
    	jiaWait(context,value){
    		console.log('actions中的jiaWait被调用了')
    		setTimeout(()=>{
    			context.commit('JIA',value)
    		},500)
    	}
    }
    //准备mutations——用于操作数据(state)
    const mutations = {
    	JIA(state,value){
    		console.log('mutations中的JIA被调用了')
    		state.sum += value
    	},
    	JIAN(state,value){
    		console.log('mutations中的JIAN被调用了')
    		state.sum -= value
    	}
    }
    //准备state——用于存储数据
    const state = {
    	sum:0 //当前的和
    }
    //准备getters——新添加,用于将state中的数据进行加工
    const getters = {
    	bigSum(state){
    		return state.sum*10
    	}
    }
    
    //创建并暴露store
    export default new Vuex.Store({
    	actions,
    	mutations,
    	state,
    	getters  //新添加
    })
    
    
  3. 组件中读取数据:$store.getters.bigSum

    Count.vue

    <template>
    	<div>
    		<h1>当前求和为:{{$store.state.sum}}</h1>
    		<h3>当前求和放大10倍为:{{$store.getters.bigSum}}</h3>
    		<select v-model.number="n">
    			<option value="1">1</option>
    			<option value="2">2</option>
    			<option value="3">3</option>
    		</select>
    		<button @click="increment">+</button>
    		<button @click="decrement">-</button>
    		<button @click="incrementOdd">当前求和为奇数再加</button>
    		<button @click="incrementWait">等一等再加</button>
    	</div>
    </template>
    
    <script>
    	export default {
    		name:'Count',
    		data() {
    			return {
    				n:1, //用户选择的数字
    			}
    		},
    		methods: {
    			increment(){
    				this.$store.commit('JIA',this.n)
    			},
    			decrement(){
    				this.$store.commit('JIAN',this.n)
    			},
    			incrementOdd(){
    				this.$store.dispatch('jiaOdd',this.n)
    			},
    			incrementWait(){
    				this.$store.dispatch('jiaWait',this.n)
    			},
    		},
    		mounted() {
    			console.log('Count',this.$store)
    		},
    	}
    </script>
    
    <style lang="css">
    	button{
    		margin-left: 5px;
    	}
    </style>
    
    

6.6 四个map方法的使用

导入

import {mapState, mapGetters, mapActions, mapMutations} from 'vuex'

  1. mapState方法:用于帮助我们映射state中的数据为计算属性

    computed: {
        //借助mapState生成计算属性:sum、school、subject(对象写法)
         ...mapState({sum:'sum',school:'school',subject:'subject'}),
             
        //借助mapState生成计算属性:sum、school、subject(数组写法)
        ...mapState(['sum','school','subject']),
    },
    
    
  2. mapGetters方法:用于帮助我们映射getters中的数据为计算属性

    computed: {
        //借助mapGetters生成计算属性:bigSum(对象写法)
        ...mapGetters({bigSum:'bigSum'}),
    
        //借助mapGetters生成计算属性:bigSum(数组写法)
        ...mapGetters(['bigSum'])
    },
    
    
  3. mapActions方法:用于帮助我们生成与actions对话的方法,即:包含$store.dispatch(xxx)的函数

    methods:{
        //靠mapActions生成:incrementOdd、incrementWait(对象形式)
        ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
    
        //靠mapActions生成:incrementOdd、incrementWait(数组形式)
        ...mapActions(['jiaOdd','jiaWait'])
    }
    
    
  4. mapMutations方法:用于帮助我们生成与mutations对话的方法,即:包含$store.commit(xxx)的函数

    methods:{
        //靠mapActions生成:increment、decrement(对象形式)
        ...mapMutations({increment:'JIA',decrement:'JIAN'}),
        
        //靠mapMutations生成:JIA、JIAN(对象形式)
        ...mapMutations(['JIA','JIAN']),
    }
    
    

备注:mapActions与mapMutations使用时,若需要传递参数需要:在模板中绑定事件时传递好参数,否则传的参数是事件对象(event)。

具体案例:

<template>
  <div>
    <h1>当前求和为:{{ sum }}</h1>
    <h3>当前求和放大10倍为:{{ bigSum }}</h3>
    <h3>年龄:{{ age }}</h3>
    <h3>姓名:{{name}}</h3>
    <select v-model.number="n">
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
    </select>
	<!-- 用了mapActions 和 mapMutations 的话要主动传参 -->
    <button @click="increment(n)">+</button>
    <button @click="decrement(n)">-</button>
    <button @click="incrementOdd(n)">当前求和为奇数再加</button>
    <button @click="incrementWait(n)">等一等再加</button>
  </div>
</template>

<script>
import { mapState, mapGetters, mapActions, mapMutations } from 'vuex'
export default {
  name: "Count",
  data() {
    return {
      n: 1, //用户选择的数字
    };
  },
  computed: {
	...mapState(['sum', 'age', 'name']),
	...mapGetters(['bigSum'])  
  },
  methods: {
    ...mapActions({incrementOdd: 'sumOdd', incrementWait: 'sumWait'}),
    ...mapMutations({increment: 'sum', decrement: 'reduce'})
  },
  mounted() {
    console.log("Count", this);
  },
};
</script>

<style lang="css">
button {
  margin-left: 5px;
}
</style>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值