一、Vue注入
1.1 注入概念
配置对象中的部分内容会被提取到Vue实例中:data、methods,该过程称之为注入。
如下代码
<!DOCTYPE html>
<html lang="en">
<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">
<!-- 界面模板 -->
<!-- mustache -->
<h1>系统名称:{{title}}</h1>
<ul>
<!-- v-for 指令-->
<li v-for="(item,i) in products">
名称:{{item.name}}
<button @click="changeStock(item,item.stock-1)">-</button>
<span v-if="item.stock>0">{{item.stock}}</span>
<span v-else>无货</span>
<button @click="changeStock(item,item.stock+1)">+</button>
<button @click="remove(i)">删除</button>
</li>
</ul>
</div>
<script src="./vue.min.js" ></script>
<script>
// vm:Vue实例
var vm = new Vue({ //配置对象
el:"#app", // css选择器
data:{ //和界面相关的数据
title:"库存管理系统",
products:[
{name:"iphone",stock:10},
{name:"xiaomi",stock:5},
{name:"huawei",stock:6},
],
},
methods:{
remove(i){
this.products.splice(i,1);
},
changeStock(product,newStock){
if(newStock<0){
newStock = 0;
}
product.stock = newStock;
}
},
});
</script>
</body>
</html>
注入
1.2 注入目的
注入目的有两个
- 完成数据响应式
- 绑定this
1.3 数据响应式vue是怎么知道数据被更改了?
vue2.0
是通过Object.defineProperty
方法完成了数据响应式(更改数据后会调用该方法),这个是ES5的方式。
vue3.0
是通过Class Proxy
完成的数据响应式。
Class Proxy
比 Object.defineProperty
效率更高,Object.defineProperty
有天生的缺陷,新增或删除了属性,Object.defineProperty
无法感知
1.3.1 新增属性无感知,界面不会重新渲染
添加一个<p>{{abc}}</p>
标签,abc
这个属性暂时不存在,页面会报错,我们动态添加abc
属性,并赋值为123,但页面没有显示出123的p标签,因此新增属性无感知,界面不会重新渲染。
1.3.2 删除属性无感知,界面不会重新渲染
我们动态删除第一项的产品,delete vm.products[0]
,界面没有重新渲染。
1.4 注入目的绑定this
// vm:Vue实例
var vm = new Vue({ //配置对象
el:"#app", // css选择器
data:{ //和界面相关的数据
title:"库存管理系统",
products:[
{name:"iphone",stock:10},
{name:"xiaomi",stock:5},
{name:"huawei",stock:6},
],
},
methods:{
remove(i){
this.products.splice(i,1);
},
},
});
remove
方法中的this,按道理来说,应该指向的是methods
,但现在指向的是vm实例。原因是methods.remove
先提取到Vue实例中了,并绑定了this
为vm
,类似于 methods.remove.bind(vm)
二、虚拟DOM树
2.1 虚拟DOM树概览
为了提高渲染效率,Vue会把模板编译为虚拟DOM树,然后再生成真实的DOM
模板-虚拟DOM-真实DOM用console.dir(document.body)
可以打印出真实DOM树结构
用vm._vnode
可查看虚拟DOM
当数据更改时,将重新编译成虚拟DOM树,然后对前后两棵树进行对比,仅将差异部分反映到真实DOM,这样即可最小程度的改动真实DOM,提升页面效率。
diff算法2.2 提升Vue效率
因此,对于vue而言,提升效率重点着眼于两个方面:
- 减少新的虚拟DOM的生成
- 保证对比之后,只有必要的节点有变化
2.3 Vue生成虚拟DOM树的方式
Vue提供了多种方式生成虚拟DOM树
1、在挂载的元素内部直接书写,此时将使用元素的outerHTML作为模板
2、在template配置中书写
在配置里加template
<!DOCTYPE html>
<html lang="en">
<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">
</div>
<script src="./vue.min.js" ></script>
<script>
// vm:Vue实例
var vm = new Vue({ //配置对象
el:"#app", // css选择器
template:`
<div id ="app">
<!-- 界面模板 -->
<!-- mustache -->
<h1>系统名称:{{title}}</h1>
<ul>
<!-- v-for 指令-->
<li v-for="(item,i) in products">
名称:{{item.name}}
<button @click="changeStock(item,item.stock-1)">-</button>
<span v-if="item.stock>0">{{item.stock}}</span>
<span v-else>无货</span>
<button @click="changeStock(item,item.stock+1)">+</button>
<button @click="remove(i)">删除</button>
</li>
</ul>
</div>
`,
data:{ //和界面相关的数据
title:"库存管理系统",
products:[
{name:"iphone",stock:10},
{name:"xiaomi",stock:5},
{name:"huawei",stock:6},
],
},
methods:{
remove(i){
this.products.splice(i,1);
},
changeStock(product,newStock){
if(newStock<0){
newStock = 0;
}
product.stock = newStock;
}
},
});
</script>
</body>
</html>
3、在render配置中用函数直接创建虚拟节点树,此时,完全脱离模板,将省略编译步骤
写render
方法
<!DOCTYPE html>
<html lang="en">
<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">
</div>
<script src="./vue.min.js" ></script>
<script>
// vm:Vue实例
var vm = new Vue({ //配置对象
el:"#app", // css选择器
render(h){
return h("div",[
h("h1",this.title),
h("p","首页")
]);
},
data:{ //和界面相关的数据
title:"库存管理系统",
},
});
</script>
</body>
</html>
render方式
我们可以用这种方式动态生成6级标题
<!DOCTYPE html>
<html lang="en">
<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">
</div>
<script src="./vue.min.js" ></script>
<script>
// vm:Vue实例
var vm = new Vue({ //配置对象
el:"#app", // css选择器
render(h){
var titles = [];
for(var i = 1;i<=6;i++){
titles.push(h(`h${i}`,`${i}级标题`));
}
return h("div",titles);
},
data:{ //和界面相关的数据
title:"库存管理系统",
},
});
</script>
</body>
</html>
动态生成6级标题
这些步骤从上到下,优先级逐渐提升
注意:虚拟节点树必须是单根的
原因是diff算法只能对比前后两棵树,如果是多根节点,则会生成多棵树,diff算法无法对比。
三、挂载
将生成的真实DOM树,放置到某个元素位置,称之为挂载。挂载的方式:
1、通过el:"css选择器"
进行配置
2、通过vue实例.$mount("css选择器")
进行配置
四、完整流程
完整流程源码
源码 001
网友评论