vue非常详细基基基基基础

1、el挂载点和data

el选项命中的元素及其内部的后代元素,可以使用其他的选择器,但是建议使用id选择器
data中可以写复杂类型的数据,渲染复杂类型数据时,遵守js的语法就可以

<body>
    <div id="app">
        {{message}}
        <span>{{message}}</span>
    </div>
    <div class="app2">
        {{message}}
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        var app=new Vue({
            el:"#app",//挂载点el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串。
            data:{
                message:"hello vue"//data中用于存储数据,数据供el所指定的容器去使用,值我们暂时先写成一个对象。
            }
        });
        var app2=new Vue({
            el:".app2",
            data:{
                message:"hello vue2"
            }
        })
    </script>
</body>

在这里插入图片描述


<body>
    <div id="app">
        {{message}}
        <h2>
            {{stus.name[1]}}
        </h2>
        <h3>
            {{stus.name[2]}}
        </h3>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        var app=new Vue({
            el:"#app",
            data:{
                message:"hello data",
                stus:{
                    name:["mike","amy","jack"],
                    num:111111111
                },
                city:["guangzhou","beijing","shanghai"]

            }
        })
    </script>
</body>

在这里插入图片描述

1.2 容器和实例是一对一的

创建vue实例接管容器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div id="app">
        {{message}} {{message2}}
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
       new Vue({
            el:"#app",//挂载点
            data:{
                message:"hello vue"
            }
        });
        new Vue({
            el:"#app",//挂载点
            data:{
                message2:"hello vue222"
            }
        });
    </script>
</body>
</html>

在这里插入图片描述
容器和实例是一一对应的
初识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(){}

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>初识Vue</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<div id="demo">
			<h1>Hello,{{name.toUpperCase()}},{{address}}</h1>
		</div>

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

			//创建Vue实例
			new Vue({
				el:'#demo', //el用于指定当前Vue实例为哪个容器服务,值通常为css选择器字符串。
				data:{ //data中用于存储数据,数据供el所指定的容器去使用,值我们暂时先写成一个对象。
					name:'atguigu',
					address:'北京'
				}
			})

		</script>
	</body>
</html>

1.3 模板语法

Vue模板语法有2大类:

1. 插值语法:
功能:用于解析标签体内容
写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性。
2. 指令语法:
功能:用于解析标签(包括:标签属性标签体内容绑定事件…)。
举例:v-bind:href=“xxx” 或 简写为 :href=“xxx”,xxx同样要写js表达式,且可以直接读取到data中的所有属性把xxx当js表达式执行
备注:Vue中有很多的指令,且形式都是:v-???

<!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">
			<h1>插值语法</h1>
			<h3>你好,{{name}}</h3>
			<hr/>
			<h1>指令语法</h1>
			<a v-bind:href="school.url.toUpperCase()" x="hello">点我去{{school.name}}学习1</a>
			<a :href="school.url" x="hello">点我去{{school.name}}学习2</a>
		</div>
	</body>

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

		new Vue({
			el:'#root',
			data:{
				name:'jack',
				school:{
					name:'',
					url:'http://www.baidu.com',
				}
			}
		})
	</script>
</html>

在这里插入图片描述
而x还是固定写死的值
在这里插入图片描述

1.4 单向数据绑定

  1. 语法:v-bind:href ="xxx" 或简写为 :href
    把"xxx"当表达式在data中读取href
    特点:数据只能从 data 流向页
<!-- 普通写法 -->
<input type="text" v-bind:value="name"><br/>
<!-- 简写 -->
单向数据绑定:<input type="text" :value="name"><br/>

1.5 双向数据绑定

  1. 语法:v-mode:value="xxx" 或简写为 v-model="xxx"
  2. 特点:数据不仅能从 data 流向页面,还能从页面流向 data
	<!-- 普通写法 -->
<input type="text" v-model:value="name"><br/> -->
<!-- 简写 -->
双向数据绑定:<input type="text" v-model="name"><br/>
<!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">
		</div>
	</body>

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

		new Vue({
			el:'#root',
			data:{
				name:'Jack'
			}
		})
	</script>
</html>

在这里插入图片描述
第二行改变会影响第一行,因为是双向绑定,但是第一行修改不会影响第二行

如下代码是错误的,因为v-model只能应用在表单类元素(输入类元素)上

 <h2 v-model:x="name">你好啊</h2> 

1.6 el与data的两种写法

  1. el有2种写法
    (1).new Vue时候配置el属性。
    (2).先创建Vue实例,随后再通过vm.$mount(’#root’)指定el的值。mount意思有挂载
//第一种写法
new Vue({
el:'#root', 
data:{
	name:'Jack'
	}
})
//第二种写法 */
const v = new Vue({
data:{
	name:'Jack'
	}
})
	v.$mount('#root') 
  1. data有2种写法
    (1).对象式
    (2).函数式
    如何选择:目前哪种写法都可以,以后学习到组件时,data必须使用函数式,否则会报错。
  2. 一个重要的原则:
    由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了。而是指向window
new Vue({
			el:'#root',
			//data的第一种写法:对象式
			 data:{
				name:'Jack'
			} 
		})
new Vue({
			el:'#root',
			//data的第二种写法:函数式
			data:function(){
				console.log('@@@',this) 
				//此处的this是Vue实例对象
				return{
					name:'Jack'
				}
			}
		})
<!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">
		new Vue({
			el:'#root',
			data:function(){
				console.log('@@@',this) 
				return{
					name:'Z'
				}
			}
		})
	</script>
</html>

在这里插入图片描述
data函数不能写成箭头函数
在这里插入图片描述

1.7 MVVM

vue参考了MVVM
MVVM模型

  1. M:模型(Model) :data中的数据
  2. V:视图(View) :模板代码
  3. VM:视图模型(ViewModel):Vue实例

观察发现:

  1. data中所有的属性,最后都出现在了vm身上。
  2. vm身上所有的属性 及 Vue原型上所有属性,在Vue模板中都可以直接使用
    在这里插入图片描述
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>理解MVVM</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<div id="root">
			<h1>学校名称:{{name}}</h1>
			<h1>学校地址:{{address}}</h1>
			<!-- <h1>测试一下1{{1+1}}</h1>
			<h1>测试一下2{{$options}}</h1>
			<h1>测试一下3{{$emit}}</h1>
			<h1>测试一下4{{_c}}</h1> -->
		</div>
	</body>

	<script type="text/javascript">
		const vm = new Vue({
			el:'#root',
			data:{
				name:'北大',
				address:'北京',
			}
		})
		console.log(vm)
	</script>
</html>

在这里插入图片描述
在这里插入图片描述
vm身上有adress和name
在这里插入图片描述

1.8 数据代理

1.8.1 Object.defineproperty

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

  1. 语法
Object.defineProperty(obj, prop, descriptor)
  • 参数
    obj 要定义属性的对象。
    prop 要定义或修改的属性的名称或 Symbol 。
    descriptor 要定义或修改的属性描述符。

    • enumerable:true, //控制属性是否可以枚举,默认值是false
    • writable:true, //控制属性是否可以被修改,默认值是false
    • configurable:true //控制属性是否可以被删除,默认值是false

    返回值 被传递给函数的对象。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>回顾Object.defineproperty方法</title>
	</head>
	<body>
		<script type="text/javascript" >
			let number = 18
			let person = {
				name:'张三',
				sex:'男',
			}

			Object.defineProperty(person,'age',{
				// value:18,
				// enumerable:true, 
				// writable:true, 
				// configurable:true 
				//当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
				get(){
					console.log('有人读取age属性了')
					return number
				},

				//当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
				set(value){
					console.log('有人修改了age属性,且值是',value)
					number = value
				}

			})
			console.log(Object.keys(person))
			console.log(person)
		</script>
	</body>
</html>

在这里插入图片描述
在这里插入图片描述

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>回顾Object.defineproperty方法</title>
	</head>
	<body>
		<script type="text/javascript" >
			let number = 18
			let person = {
				name:'张三',
				sex:'男',
                age:18
			}
            console.log(Object.keys(person));
            for(key in person)
            {
                console.log(person[key]);
            }
			console.log(person)
		</script>
	</body>
</html>

在这里插入图片描述

默认不可迭代,不可修改,不可删除

1.8.1 数据代理

数据代理:通过一个对象代理对另一个对象中属性的操作(读/写)

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>何为数据代理</title>
	</head>
	<body>
		<script type="text/javascript" >
			let obj = {x:100}
			let obj2 = {y:200}

			Object.defineProperty(obj2,'x',{
				get(){
					return obj.x
				},
				set(value){
					obj.x = value
				}
			})
		</script>
	</body>
</html>

在这里插入图片描述

1.8.3 vue中数据代理

  • 1.Vue中的数据代理:
    通过vm来代理data对象中属性的操作(读/写)
  • 2.Vue中数据代理的好处:
    更加方便的操作data中的数据 ,不然要写成_data.name
  • 3.基本原理:
    通过Object.defineProperty()把data对象中所有属性添加到vm上。
    为每一个添加到vm上的属性,都指定一个getter/setter
    getter/setter内部去操作(读/写)data中对应的属性。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>Vue中的数据代理</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<div id="root">
			<h2>名称:{{name}}</h2>
			<h2>地址:{{address}}</h2>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		const vm = new Vue({
			el:'#root',
			data:{
				name:'school',
				address:'广州'
			}
		})
		console.log(vm);
	</script>
</html>

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

2、内置指令

2.1、v-text

设置标签的文本值
3. 若使用v-text指令,将会把标签内的文字全部替换
4. 或者用差值表达式进行部分替换
5. 在v-text指令内进行字符串拼接,内部支持写表达式

<body>
    <div id="app">
        <h2 v-text="message">1111111</h2>
        <h2 v-text="name">11111111</h2>
        <h2>{{message}}11111111</h2><!--只有这个的111才显示-->
        <h2 v-text="message+'11111111'"></h2>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        var app=new Vue({
            el:"#app",
            data:{
                message:"v-text",
                name:"mike"
            }
        })
    </script>
</body>

在这里插入图片描述


2.3、v-html

设置标签的innerHTML

  • v-html指令作用式设置元素的innerHTML,内容中有html结构会被解析成标签
  • v-text指令不论是什么内容,只会解析成文本
  • 解析文本用v-text,解析html结构使用v-html
<body>
    <div id="app">
        <p v-html="baidu"></p>
        <p v-text="baidu"></p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        var app=new Vue({
            el:"#app",
           data:{
               baidu:"<a href='https://www.baidu.com/'>百度<a>"
           }
        })
    </script>
</body>

在这里插入图片描述


2. 4、v-on

为元素绑定事件

  • 绑定的方法定义在methods属性中,最终会在vm上;
  • 方法内部通过this关键字可以访问修改定义在data中的数据
  • 使用v-on:xxx 或 @xxx 绑定事件,其中xxx是事件名;
  • methods中配置的函数,不要用箭头函数!否则this就不是vm了;
  • methods中配置的函数,都是被Vue所管理的函数,this的指向是vm 或 组件实例对象;
  • @click=“demo” 和 @click=“demo($event)” 效果一致,但后者可以传参;
<body>
    <div id="app">
        <button v-on:click="sayHi">按钮</button>
        <button @click="sayHi">按钮</button>
        <button @dblclick="addReally">really</button>
      <p>  {{feeling}}</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        var app=new Vue({
            el:"#app",
            data:{
               feeling:"happy"
            },
           methods:{
               addReally:function(){
               this.feeling+="really!"
               },
              sayHi:function(){
                  alert("你好呀");
              }
           }
        })
    </script>
</body>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. 4.1 传递参数

  • 事件绑定的方法写成函数调用的形式,可以自定义传入参数
  • 定义方法时需要定义形参来接受传入的实参
  • 事件后面跟上.修饰符可以对事件进行修饰,eg:.enter可以限制触发的按键为回车键
  • 事件修饰符有多种
<div id="app">
<input type="button" @click="doit(p1,p2)"/>
<input type="text" @keyup.enter="sayHi">
</div>
<script>
    var app=new Vue({
        el:"#app",
        methods:{
            doit:function(p1,p2){

            },
            sayHi:function(){
                
            }
        }
    })
</script>

2. 4.2 事件修饰符

Vue中的事件修饰符:

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

a标签默认会跳转,阻止以后不会跳转

	<!-- 阻止默认事件(常用) -->
<a href="https://www.bilibili.com/" @click.prevent="showInfo">点我提示信息</a>

事件只触发一次(常用)

 <button @click.once="showInfo">点我提示信息</button>

2. 5、计数器

<body>
    <div id="app">
       <button @click="sub">-</button>
       <span>{{ num }}</span>
       <button @click="add">+</button>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        var app=new Vue({
            el:"#app",
           data:{
              num:1
           },
           methods:{
               add:function(){
                if(this.num<=9)
                {
                    this.num++;
                }
                else{
                    alert("数量已经达到上限啦!");
                }
               },
               sub:function(){
                   if(this.num>=1)
                   {
                       this.num--;
                   }
                   else{
                       alert("数量已经达到下限啦!");
                   }

               }
           }
        })
    </script>
</body>

在这里插入图片描述
在这里插入图片描述

2. 6、v-show

根据表达式的真假,切换元素的显示和隐藏

<div id="app">
<img src="#" alt="" v-show="true">
<img src="#" alt="" v-show="isShow">
<img src="#" alt="age>=18">
</div>
var app=new Vue({
    el:"#app",
    data:{
        isShow:false,
        age:16
    }
})
  • v-show原理式修改元素的display,实现显示隐藏
  • 指令后面的值,最后会被解析成布尔值
  • 数据改变后,元素的显示状态会同步更新
<body>
    <div id="app">
       <img src="/img/yellow.png" v-show="isShow">
       <button @click="doit">点击</button>
       <img src="/img/yellow.png" v-show="num==5">
       <button @click="sub">-</button>
       <span>{{num}}</span>
       <button @click="add">+</button>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        var app=new Vue({
            el:"#app",
           data:{
              isShow:true,
              num:0
           },
           methods:{
            doit:function(){
                this.isShow=!this.isShow;
            },
            add:function(){
                this.num++;
            },
            sub:function(){
                this.num--;
            }
           }
        })
    </script>
</body>

在这里插入图片描述
在这里插入图片描述

2. 7、v-if

根据表达式的真假,切换元素的显示和隐藏(操作dom元素)

  • 表达式的值为true,元素存在在dom中,为false,在dom树中移除
    -频繁的切换使用v-show,消耗比较小,反之使用v-if
<body>
    <!--if是直接移除样式,show是改变display-->
    <div id="app">
      <p v-if="isShow">今天是星期六</p>
      <button @click="clickIt">按钮</button>
      <p v-if="num>=20">明天是星期天</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        var app=new Vue({
            el:"#app",
            data:{
              isShow:true,
              num:2
            },
           methods:{
               clickIt:function(){
                   this.isShow=!this.isShow;
               }
              
           }
        })
    </script>
</body>

2. 8、v-bind

设置元素的属性(比如src,title,class)

  • 完整写法是v-bind:属性名
  • 简写的华可以省略v-bind只保留:属性名
  • 需要动态的增删class建议使用对象的方式
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .active{
            border: 10px solid red;
        }
    </style>
</head>
<body>
    <div id="app">
      <img v-bind:src="imgSrc" alt="" 
      :class="isActive?'active':''"
      @click="fan">
      <br><br><br>
      <img :src="imgSrc" alt="" :title="imgT+'!!'" 
      @click="fan" :class="{active:isActive}">
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        var app=new Vue({
            el:"#app",
            data:{
             imgSrc:"/img/yellow.png",
             imgT:"鸭子",
             isActive:false
            },
           methods:{
               fan:function(){
                   this.isActive=!this.isActive;
               }
               
           }
        })
    </script>
</body>

2. 8.2、绑定样式

class 绑定

  1. :class=‘xxx’
  2. 表达式是字符串: ‘classA’
  3. 表达式是对象: {classA:isA, classB: isB}
  4. 表达式是数组: [‘classA’, ‘classB’]

style 绑定

  1. :style="{ color: activeColor, fontSize: fontSize + ‘px’ }"
  2. 其中 activeColor/fontSize 是 data 属性
<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>

2. 9、图片切换

<body>
    <div id="app">
      <img :src="imgSrc[num]" alt="">
      <br><br><br>
      <button v-show="num!=0" @click="sub">上一页</button>
      <button v-show="num!=3" @click="add">下一页</button>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        var app=new Vue({
            el:"#app",
           data:{
               imgSrc:["/img/1.jpg","/img/2.jpg","/img/3.jpg","/img/4.jpg"],
               num:0
            
           },
           methods:{
               add:function(){
               this.num++;
               },
               sub:function(){
                this.num--;
               }
          
           }
        })
    </script>
</body>

2. 10、v-for

2.10.1、根据数据生成列表结构

  • 数组经常和v-for结合使用
  • v-for="(item, index) in xxx" :key=“yyy”
  • item和index可以结合其他指令一起使用
  • 数组长度的更新会同步到页面上,是响应式的
<body>
    <div id="app">
        <button  @click="add">增加数据</button>
        <button @click="sub">移除数据</button>
       <ul>
           <li v-for="(item,index) in arr">
               {{item}}{{index+1}}
           </li>
       </ul>
       <h2 v-for="(it,index) in vegetable" :title="it.name">
           {{it.name}}
       </h2>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        var app=new Vue({
            el:"#app",
            data:{
               arr:["北京","广州","上海","深圳"],
               vegetable:[
                   {name:"potato"},
                   {name:"tomato"},
                   {name:"cabage"}
               ]
            },
           methods:{
               add:function(){
                this.vegetable.push({name:"peach"});
               },
               sub:function(){
                this.vegetable.shift();//移除最左边的
               }
              
           }
        })
    </script>
</body>

2.10.2、key的内部原理

面试题:react、vue中的key有什么作用?(key的内部原理)

  1. 虚拟DOM中key的作用:
    key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】, 随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较,比较规则如下:
  2. .对比规则:
    (1).旧虚拟DOM中找到了与新虚拟DOM相同的key:
    ①.若虚拟DOM中内容没变, 直接使用之前的真实DOM!
    ②.若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM。
    (2).旧虚拟DOM中未找到与新虚拟DOM相同的key
    创建新的真实DOM,随后渲染到到页面。
  3. 用index作为key可能会引发的问题:
    (1)若对数据进行:逆序添加、逆序删除等破坏顺序操作:会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
    (2)如果结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题。
  4. 开发中如何选择key?:
    1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
    2.如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,用index作为key是没有问题的。

2.10.3、列表过滤

<!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>人员列表</h2>
			<input type="text" placeholder="请输入名字" v-model="keyWord">
			<ul>
				<li v-for="(p,index) of filPerons" :key="index">
					{{p.name}}-{{p.age}}-{{p.sex}}
				</li>
			</ul>
		</div>

		<script type="text/javascript">
			Vue.config.productionTip = false
			//用computed实现
			new Vue({
				el:'#root',
				data:{
					keyWord:'',
					persons:[
						{id:'001',name:'马冬梅',age:19,sex:'女'},
						{id:'002',name:'周冬雨',age:20,sex:'女'},
						{id:'003',name:'周杰伦',age:21,sex:'男'},
						{id:'004',name:'温兆伦',age:22,sex:'男'}
					]
				},
				computed:{
					filPerons(){
						return this.persons.filter((p)=>{
							return p.name.indexOf(this.keyWord) !== -1
						})
					}
				}
			}) 
		</script>
</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>人员列表</h2>
			<input type="text" placeholder="请输入名字" v-model="keyWord">
			<ul>
				<li v-for="(p,index) of filPerons" :key="index">
					{{p.name}}-{{p.age}}-{{p.sex}}
				</li>
			</ul>
		</div>
		<script type="text/javascript">
			Vue.config.productionTip = false
		new Vue({
				el:'#root',
				data:{
					keyWord:'',
					persons:[
						{id:'001',name:'马冬梅',age:19,sex:'女'},
						{id:'002',name:'周冬雨',age:20,sex:'女'},
						{id:'003',name:'周杰伦',age:21,sex:'男'},
						{id:'004',name:'温兆伦',age:22,sex:'男'}
					],
					filPerons:[]
				},
				watch:{
					keyWord:{
						immediate:true,
						handler(val){
							this.filPerons = this.persons.filter((p)=>{
								return p.name.indexOf(val) !== -1
							})
						}
					}
				}
			}) 
		</script>
</html>

2. 10.4、列表排序

<!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>人员列表</h2>
			<input type="text" placeholder="请输入名字" v-model="keyWord">
			<button @click="sortType = 2">年龄升序</button>
			<button @click="sortType = 1">年龄降序</button>
			<button @click="sortType = 0">原顺序</button>
			<ul>
				<li v-for="(p,index) of filPerons" :key="p.id">
					{{p.name}}-{{p.age}}-{{p.sex}}
					<input type="text">
				</li>
			</ul>
		</div>

		<script type="text/javascript">
			Vue.config.productionTip = false
			
			new Vue({
				el:'#root',
				data:{
					keyWord:'',
					sortType:0, //0原顺序 1降序 2升序
					persons:[
						{id:'001',name:'马冬梅',age:30,sex:'女'},
						{id:'002',name:'周冬雨',age:31,sex:'女'},
						{id:'003',name:'周杰伦',age:18,sex:'男'},
						{id:'004',name:'温兆伦',age:19,sex:'男'}
					]
				},
				computed:{
					filPerons(){
						const arr = this.persons.filter((p)=>{
							return p.name.indexOf(this.keyWord) !== -1
						})
						//判断一下是否需要排序
						if(this.sortType){
							arr.sort((p1,p2)=>{
								return this.sortType === 1 ? p2.age-p1.age : p1.age-p2.age
							})
						}
						return arr
					}
				}
			}) 

		</script>
</html>

2.11、v-model

设置和获取表单元素的值(双向数据绑定)

  • 绑定的数据会和表单元素的值相互关联
  • v-model的三个修饰符:
    (1)lazy:失去焦点再收集数据
    (2)number:输入字符串转为有效的数字
    (3)trim:输入首尾空格过滤v-model.trim="userInfo.account"
<body>
    <div id="app">
        <button @click="setV">修改</button>
      <input type="text"v-model="message" @keyup.enter="add">
    <h2>{{message}}</h2><!--双向数据绑定-->
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        var app=new Vue({
            el:"#app",
            data:{
               message:"冲冲冲"
            },
           methods:{
               add:function(){
                   alert(this.message);
               },
               setV:function(){
                   this.message="不会的都可以学";
                   alert(this.message);
               }
              
           }
        })
    </script>
</body>

在这里插入图片描述

2.11、v-cloak

v-cloak指令(没有值):
1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-cloak指令</title>
	</head>
	<script type="text/javascript"src="http://localhost:8080/resource/5s/vue.js"></script>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2 v-cloak>{{name}}</h2>
		</div>
	</body>
	<script type="text/javascript">
		console.log(1)
		new Vue({
			el:'#root',
			data:{
				name:'尚硅谷'
			}
		})
	</script>
</html>

这时会有js阻塞,5s后控制台才输出1

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-cloak指令</title>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2 v-cloak>{{name}}</h2>
		</div>
	<script type="text/javascript"src="http://localhost:8080/resource/5s/vue.js"></script>
	</body>
	<script type="text/javascript">
		console.log(1)
		new Vue({
			el:'#root',
			data:{
				name:'尚硅谷'
			}
		})
	</script>
</html>

会有没解析的模板出现在页面,5秒后才渲染
在这里插入图片描述
在没设置样式前,网页还是会呈现为接管的代码,一旦vue接管了代码,v-cloak就会被删除,结合样式,可以让未接管的代码不显示,可以在网速过慢的时候,页面显示未解析的代码

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-cloak指令</title>
		<style>
			[v-cloak]{
				display:none;
			}
		</style>
		<!-- 引入Vue -->
	</head>
	<body>
		<div id="root">
			<h2 v-cloak>{{name}}</h2>
		</div>
		<script type="text/javascript" src="http://localhost:8080/resource/5s/vue.js"></script>
	</body>
	<script type="text/javascript">
		console.log(1)
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		new Vue({
			el:'#root',
			data:{
				name:'尚硅谷'
			}
		})
	</script>
</html>

2.12、v-once

v-once指令:
1.v-once所在节点在初次动态渲染后,就视为静态内容了。
2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-once指令</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<div id="root">
			<h2 v-once>初始化的n值是:{{n}}</h2>
			<h2>当前的n值是:{{n}}</h2>
			<button @click="n++">点我n+1</button>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		new Vue({
			el:'#root',
			data:{
				n:1
			}
		})
	</script>
</html>

在这里插入图片描述

2.12、v-pre

1.跳过其所在节点的编译过程
2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-pre指令</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<div id="root">
			<h2 v-pre>Vue其实很简单</h2>
			<h2 >当前的n值是:{{n}}</h2>
			<button @click="n++">点我n+1</button>
		</div>
	</body>

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

		new Vue({
			el:'#root',
			data:{
				n:1
			}
		})
	</script>
</html>

在这里插入图片描述
会跳过其所在节点的编译过程,显示未解析的代码

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-pre指令</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<div id="root">
			<h2 v-pre>Vue其实很简单</h2>
			<h2  v-pre>当前的n值是:{{n}}</h2>
			<button @click="n++" v-pre>点我n+1</button>
		</div>
	</body>

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

		new Vue({
			el:'#root',
			data:{
				n:1
			}
		})
	</script>
</html>

在这里插入图片描述

3、自定义指令

一、定义语法:
(1).局部指令:

new Vue({
directives:{指令名:配置对象}或directives{指令名:回调函数}
}) 

(2).全局指令:

Vue.directive(指令名,配置对象) 或   Vue.directive(指令名,回调函数)

二、配置对象中常用的3个回调:
(1).bind:指令与元素成功绑定时调用。
(2).inserted:指令所在元素被插入页面时调用。
(3).update:指令所在模板结构被重新解析时调用。
三、备注:
1.指令定义时不加v-,但使用时要加v-;
2.指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。

需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<div id="root">
			<h2>{{name}}</h2>
			<h2>当前的n值是:<span v-text="n"></span> </h2>
			<h2>放大10倍后的n值是:<span v-big="n"></span> </h2>
			<button @click="n++">点我n+1</button>
		</div>
	</body>
<script type="text/javascript">
		Vue.config.productionTip = false
		new Vue({
			el:'#root',
			data:{
				name:'learn',
				n:1
			},
            directives:{
                big(element,binding){
                    console.log(element,binding);
                }
            }
			
		})
		
	</script>
</html>

element是真实的dom,binding.value是1,一开始n等于1。由于v-big绑定的是“n”,所以expression显示为“n”

<span v-big="n">

在这里插入图片描述

<script type="text/javascript">
		Vue.config.productionTip = false
		new Vue({
			el:'#root',
			data:{
				name:'learn',
				n:1
			},
            directives:{
                big(element,binding){
                  element.innerText=binding.value*10
                }
            }
			
		})
		
	</script>

在这里插入图片描述

big函数何时调用
自定义指令写成函数式时只有在下面两种方式下被调用

  1. 指令与元素成功绑定时(以上来)
  2. 指令所在模板被重新解析,像上面的如果只更改name属性的值,big函数还是会被调用。

需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<div id="root">
			<h2>{{name}}</h2>
			<h2>当前的n值是:<span v-text="n"></span> </h2>
			<h2>放大10倍后的n值是:<span v-big="n"></span> </h2>
			<button @click="n++">点我n+1</button>
            <hr/>
            <input type="text" v-fbind:value="n">
		</div>
	</body>
<script type="text/javascript">
		Vue.config.productionTip = false
		new Vue({
			el:'#root',
			data:{
				name:'learn',
				n:1
			},
            directives:{
                big(element,binding){
                    element.innerText=binding.value*10
                },
                fbind(element, binding){
                    element.value=binding.value;
                    element.focus();
                }
            }
			
		})
		
	</script>
</html>

页面初始化第一次的时候并没有获取焦点
在这里插入图片描述
因为input只是和find绑定,还没渲染到页面,所以element.focus()无效,第二次第三次点击按钮,n值变化,指令所在模板被重新解析,find函数被重新调用

写成对象式

			//指令与元素成功绑定时(一上来)
			bind(element,binding){
			},
			//指令所在元素被插入页面时
			inserted(element,binding){
			},
			//指令所在的模板被重新解析时
			update(element,binding){
			}
<script type="text/javascript">
		Vue.config.productionTip = false
		new Vue({
			el:'#root',
			data:{
				name:'learn',
				n:1
			},
            directives:{
                big(element,binding){
                    element.innerText=binding.value*10
                },
                fbind:{
			bind(element,binding){
				element.value = binding.value
			},
			inserted(element,binding){
				element.focus()
			},
			update(element,binding){
				element.value = binding.value
			}
                }
            }
			
		})
		
	</script>

完整写法

/* 'big-number'(element,binding){
	console.log('big',this) //注意此处的this是window
// console.log('big')
element.innerText = binding.value * 10
}, */
  • 如果用破折号连接就要用上面的写法,如果写v-bigNumber不会生效
  • 指令里的this指向的是window
	<h2>放大10倍后的n值是:<span v-bigNumber="n"></span> </h2>

1.指令定义时不加v-,但使用时要加v-;
2.指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase驼峰命名法命名。
定义全局指令


		//定义全局指令
		/* Vue.directive('fbind',{
			//指令与元素成功绑定时(一上来)
			bind(element,binding){
				element.value = binding.value
			},
			//指令所在元素被插入页面时
			inserted(element,binding){
				element.focus()
			},
			//指令所在的模板被重新解析时
			update(element,binding){
				element.value = binding.value
			}
		}) */

3、axios基本使用

  • axios必须先导入才可以使用
  • 使用get或者post方法即可发送对应的请求
  • then方法中的回调函数会在请求成功或者失败时触发
  • 通过回调函数的形参可以获取响应内容或者错误内容
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/3.0.7/vue.cjs.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.js"></script>
</head>
<body>
    <input type="button" value="get请求">
    <input type="button" value="post请求">
    <script>
        const input=document.querySelectorAll('input');
        input[0].onclick=function(){
            axios.get("https://autumnfish.cn/api/joke/list?num=3")
            .then(response=>{
                console.log(response.data);
            },reason=>{
                console.log(reason);

            });
        }
        input[1].onclick=function(){
            axios.post("https://autumnfish.cn/api/user/reg",
            {
                username:'盐焗鹌鹑蛋'
            }
            ).then(response=>{
                console.log(response);
            },reason=>{
                cosnole.log(reason);
            });
        }
    </script>
</body>

在这里插入图片描述
在这里插入图片描述

配合vue使用

  • axios回调函数中this的指向已经发生了改变,无法访问到data中的数据
  • 把this保存起来,回调函数中直接使用保存的this即可
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <input type="button" value="获取笑话" @click="getJoke">
        <p>{{joke}}</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.js"></script>
        <script>
            var app=new Vue({
                el:"#app",
                data:{
                    joke:"笑话"
                },
                methods:{
                    getJoke:function(){
                        var _this=this;
                        console.log(this.joke);
                        axios.get("https://autumnfish.cn/api/joke")
                        .then(function(response){
                            console.log(response);
                            console.log(response.data);
                            _this.joke=response.data;
                        },function(reason){
                            console.log(reason);
                        });//methods里最好不要用箭头函数,this指向问题
                    }
                }
            })
        </script>
</body>

在这里插入图片描述

在这里插入图片描述

4、 计算属性

  • 1.定义:要用的属性不存在,要通过已有属性计算得来。
  • 2.原理:底层借助了Objcet.defineproperty方法提供的getter和setter。
  • 3.get函数什么时候执行?
    (1).初次读取时会执行一次。
    (2).当依赖的数据发生改变时会被再次调用。
  • 4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
  • 5.备注:
    1.计算属性最终会出现在vm上,直接读取使用即可
    2.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>姓名案例_计算属性实现</title>
		<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/>
			测试:<input type="text" v-model="x"> <br/><br/>
			全名:<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:'三',
				x:'你好'
			},
			methods: {
				demo(){
				}
			},
			computed:{
				fullName:{
					get(){
						console.log('get被调用了')
						// console.log(this) //此处的this是vm
						return this.firstName + '-' + this.lastName
					},
					set(value){
						console.log('set',value)
						const arr = value.split('-')
						this.firstName = arr[0]
						this.lastName = arr[1]
					}
				}
			}
		})
	</script>
</html>

在这里插入图片描述

  • get有什么作用?
    当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
  • get什么时候调用
    1.初次读取fullName时。
    2.所依赖的数据发生变化时。
  • set什么时候调用?
    1.当fullName被修改时。
    在这里插入图片描述

4.1 简写

只读不改就用简写
完整写法

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

		const vm = new Vue({
			el:'#root',
			data:{
				firstName:'张',
				lastName:'三',
			},
			computed:{
				//完整写法
				 fullName:{
					get(){
						console.log('get被调用了')
						return this.firstName + '-' + this.lastName
					},
					set(value){
						console.log('set',value)
						const arr = value.split('-')
						this.firstName = arr[0]
						this.lastName = arr[1]
					}
				} 
			}
		})
	</script>

简写

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

		const vm = new Vue({
			el:'#root',
			data:{
				firstName:'张',
				lastName:'三',
			},
			computed:{
				fullName(){
					console.log('get被调用了')
					return this.firstName + '-' + this.lastName
				}
			}
		})
	</script>

5、监视属性

5.1、监视属性watch:

1.当被监视的属性变化时, 回调函数自动调用, 进行相关操作
2.监视的属性必须存在,才能进行监视!!
3.监视的两种写法:
(1).new Vue时传入watch配置

<!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>今天天气很{{info}}</h2>
			<button @click="changeWeather">切换天气</button>
		</div>
	</body>

	<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
				}
			},
		watch:{
				isHot:{
					immediate:true, //初始化时让handler调用一下
					//handler什么时候调用?当isHot发生改变时。
					handler(newValue,oldValue){
						console.log('isHot被修改了',newValue,oldValue)
					}
				}
			} 
		})
	</script>
</html>

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

<!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>今天天气很{{info}}</h2>
			<button @click="changeWeather">切换天气</button>
		</div>
	</body>

	<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
				}
			},
		})
		vm.$watch('isHot',{
			immediate:true, //初始化时让handler调用一下
			//handler什么时候调用?当isHot发生改变时。
			handler(newValue,oldValue){
				console.log('isHot被修改了',newValue,oldValue)
			}
		})
	</script>
</html>

在这里插入图片描述

5.2、深度监视

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

<!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">
			<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>
		</div>
	</body>
	<script type="text/javascript">
		const vm = new Vue({
			el:'#root',
			data:{
				isHot:true,
				numbers:{
					a:1,
					b:1,
				}
			},
			watch:{
				//监视多级结构中某个属性的变化
				'numbers.a':{
					handler(){
						console.log('a被改变了')
					}
				} 
			}
		})

	</script>
</html>

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

<!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">
			<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>
		</div>
	</body>
	<script type="text/javascript">
		const vm = new Vue({
			el:'#root',
			data:{
				isHot:true,
				numbers:{
					a:1,
					b:1,
				}
			},
			watch:{
				//监视多级结构中所有属性的变化
				numbers:{
				//deep:true,
					handler(){
						console.log('numbers改变了')
					}
				}
			}
		})

	</script>
</html>

如果不加deep属性,改变a和b也不会有影响,因为监测的是对象的地址,对象的地址并没有改变
备注:
(1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以,除非加deep属性!
(2).使用watch时根据数据的具体结构,决定是否采用深度监视。
在这里插入图片描述

5.3、简写

只需要handle的时候

<!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>今天天气很{{info}}</h2>
			<button @click="changeWeather">切换天气</button>
		</div>
	</body>

	<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
				}
			},
			watch:{
				//简写
				/* isHot(newValue,oldValue){
					console.log('isHot被修改了',newValue,oldValue,this)
				} */
			}
		})
		//简写,不可以写箭头函数
		/* vm.$watch('isHot',function(newValue,oldValue){
			console.log('isHot被修改了',newValue,oldValue,this)
		}) */

	</script>
</html>

5.4、computed和watch之间的区别

  • 1.computed能完成的功能,watch都可以完成。
  • 2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。watch没有返回值可以用定时器。
  • 3.两个重要的小原则:
    1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm或组件实例对象。
    2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,这样this的指向才是vm或组件实例对象。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>姓名案例_watch实现</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> <br/><br/>
		</div>
	</body>

	<script type="text/javascript">
			const vm = new Vue({
			el:'#root',
			data:{
				firstName:'张',
				lastName:'三',
				fullName:'张-三'
			},
			watch:{
				firstName(newName){
					setTimeout(()=>{
						console.log(this)
						this.fullName = newName + '-' + this.lastName
					},1000);
				},
				lastName(newName){
					this.fullName = this.firstName + '-' + newName
				}
			}
		})
	</script>
</html>

5.5、监视数据原理

Vue监视数据的原理:

  1. vue会监视data中所有层次的数据。
  2. 如何监测对象中的数据?
    通过setter实现监视,且要在new Vue时就传入要监测的数据。
    (1).对象中后追加的属性,Vue默认不做响应式处理
    (2).如需给后添加的属性做响应式,请使用如下API:
    Vue.set(target,propertyName/index,value) 或
    vm.$set(target,propertyName/index,value)
  3. 如何监测数组中的数据?
    通过包裹数组更新元素的方法实现,本质就是做了两件事:
    (1).调用原生对应的方法对数组进行更新。
    (2).重新解析模板,进而更新页面。
  4. 在Vue修改数组中的某个元素一定要用如下方法:
    (1)使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
    (2)Vue.set() 或 vm.$set()

特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 添加属性!!

6、生命周期

1.又名:生命周期回调函数、生命周期函数、生命周期钩子。
2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。
3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。
4.生命周期函数中的this指向是vm 或 组件实例对象。

<!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 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>

Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
在这里插入图片描述

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<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>
			<button @click="bye">点我销毁vm</button>
		</div>
	</body>

	<script type="text/javascript">
		new Vue({
			el:'#root',
			// template:`
			// 	<div>
			// 		<h2>当前的n值是:{{n}}</h2>
			// 		<button @click="add">点我n+1</button>
			// 	</div>
			// `,//只能一个根节点
			data:{
				n:1
			},
			methods: {
				add(){
					console.log('add')
					this.n++
				},
				bye(){
					console.log('bye')
					this.$destroy()
				}
			},
			watch:{
				n(){
					console.log('n变了')
				}
			},
			beforeCreate() {
				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')
			},
			destroyed() {
				console.log('destroyed')
			},
		})
	</script>
</html>

点击销毁以后按按钮,依然有效,vue通过dom绑定方法,即使销毁了,方法依旧还绑定着,可以继续使用
在这里插入图片描述
常用的生命周期钩子:
1.mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
2.beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。
关于销毁Vue实例
1.销毁后借助Vue开发者工具看不到任何信息。
2.销毁后自定义事件会失效,但原生DOM事件依然有效。
3.一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。

7、模块与组件

模块

  1. 理解: 向外提供特定功能的 js 程序, 一般就是一个 js 文件
  2. 为什么: js 文件很多很复杂
  3. 作用: 复用 js, 简化 js 的编写, 提高 js 运行效率

组件

  • 理解: 用来实现局部(特定)功能效果的代码集合(html/css/js/image……)
  • 为什么: 一个界面的功能很复杂
  • 作用: 复用编码, 简化项目编码, 提高运行效率

模块化
当应用中的 js 都以模块来编写的, 那这个应用就是一个模块化的应用。
组件化
当应用中的功能都是多组件的方式来编写的, 那这个应用就是一个组件化的应用,

7.1、非单文件组件

一个文件中包含n个组件
1.模板编写没有提示

  • 没有构建过程, 无法将 ES6 转换成 ES5
  • 不支持组件的 CSS
  • 真正开发中几乎不用
    Vue中使用组件的三大步骤:

7.1.1、定义组件(创建组件)

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

  • 1.el不要写,为什么? ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。
  • 2.data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。 备注:使用template可以配置组件结构。

7.1.2、注册组件

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

7.1.3、使用组件(写组件标签)

<school></school>
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<div id="root">
			<hello></hello>
			<hr>
			<h1>{{msg}}</h1>
			<hr>
			<!-- 第三步:编写组件标签 -->
			<school></school>
			<hr>
			<!-- 第三步:编写组件标签 -->
			<student></student>
		</div>

		<div id="root2">
			<hello></hello>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false

		//第一步:创建school组件
		const school = Vue.extend({
			template:`
				<div class="demo">
					<h2>学校名称:{{schoolName}}</h2>
					<h2>学校地址:{{address}}</h2>
					<button @click="showName">点我提示学校名</button>	
				</div>
			`,
			//必须使用函数式,使用对象式组件复用的时候数据会同步改变
			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'
				}
			}
		})
		
		//第二步:全局注册组件
		Vue.component('hello',hello)

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

		new Vue({
			el:'#root2',
		})
	</script>
</html>

7.1.3、注意点

1.关于组件名:
一个单词组成:

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

多个单词组成:

  • 第一种写法(kebab-case命名):my-school
  • 第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)
    备注:
    -组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。
  • 可以使用name配置项指定组件在开发者工具中呈现的名字。
    2.关于组件标签:
    第一种写法:
    第二种写法:
    备注:不用使用脚手架时,会导致后续组件不能渲染。
    3.一个简写方式:
const school = Vue.extend(options) 可简写为:const school = options

7.1.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">
		</div>
	</body>
	<script type="text/javascript">
		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:'Hello!'
				}
			}
		})
		
		//定义app组件,包含hello和shool组件
		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>
</html>

7.1.5、VueComponent

  • 上面的 school组件本质是一个名为VueComponent构造函数,且不是程序员定义的,是Vue.extend生成的。
  • 我们只需要写或,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)
  • 特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!
  • 关于this指向:
    (1).组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。
    (2).new Vue(options)配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。
  • VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。Vue的实例对象,以后简称vm。

7.1.6、原型链

//定义一个构造函数
function Demo(){
this.a = 1
this.b = 2
}
//创建一个Demo的实例对象
const d = new Demo()
console.log(Demo.prototype) //显示原型属性
console.log(d.__proto__) //隐式原型属性

在这里插入图片描述

console.log(Demo.prototype === d.__proto__)

在这里插入图片描述
程序员通过显示原型属性操作原型对象,追加一个x属性,值为99

Demo.prototype.x = 99
console.log('@',d) */

在这里插入图片描述

7.1.6、内置关系

1.一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype
实例的隐式原型属性,永远指向自己缔造者的原型对象
2.为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。
在这里插入图片描述

7.2、单文件组件

一个简单的school组件

<template>
    <div class="demo">
        <h2>
            名称:{{schoolName}}
        </h2>
        <h2>
            地址:{{address}}
        </h2>
        <button @click="showName">点击我显示学校名称</button>
    </div>
</template>
<script>
export default{
    name:'School',
     data(){
        return{
            schoolName:"北大",
            address:"北京"
        }
    },
    methods:{
        showName(){
            alert(this.schoolName)
        }

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

vscode安装了vetur后,快速生成vue模板

<v  然后回车

7.2.1、App.vue

<template>
  <div>
      <School></School>
      <Student></Student>
  </div>
</template>

<script>
//引入组件
    import School from './School.vue'
    import Student from './Student.vue'

export default {
name:"App2",
components:{
    School,
    Student
}

}
</script>

<style>

</style>

main.js和App.vue配对

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值