注入
vue会将以下配置注入到vue实例:
1、data:和界面相关的数据。
2、computed:通过已有数据计算得来的数据。
3、methods:方法。
虚拟DOM树
直接操作真实的DOM会引发严重的效率问题,vue使用虚拟DOM(vnode)的方式来描述要染的内容
vnode是一个普通的JS对象,用于描述界面上应该有什么,比如:
var vnode = {
tag = "h1",
children = [
{tag = "1", text = "hello"}
]
}
上面的对象描述了:有一个标签名为h1的节点,它有一个子节点,该子节点是一个文本,内容为"hello"
vue模板
并不是真实的DOM,它会被编译为虚拟DOM
<div id="app">
<h1>标题:{{title}}</h1>
<p>作者:{{author}}</p>
</div>
{
tag :"div",
children : [
{tag : "h1", children :[ {text : "hello"} ] },
{tag : "p", children :[ {text : "slash"} ] }
]
}
虚拟DOM树会最终生成为真实的DOM树
当数据变化后,将引发重新渲染,vue会比较新旧两棵vnode tree,找出差异,然后仅把差异部分应用到真实domtree中。
可见,在vue中,要得到最终的界面,必须要生成一个vnode tree
vue通过以下逻辑生成vnode tree:
是否有render?有:运行render函数,将函数返回的结果直接作为虚拟节点树。没有:是否有template?有:将template配置作为模板,然后编译为render函数。没有:将el配置的outerHTML作为模板。
注意:虚拟节点树必须是单根的。
挂载
将生成的真实DOM树,放置到某个元素位置,称之为挂载。
挂载的方式
通过 el:"css选择器" 进行配置
通过 vue实例.$mount("css选择器")进行配置
完整流程
1、实例被创建
2、注入
3、编译生成虚拟DOM树
4、挂载
5、已挂载
6、如果数据变动,响应式 重新渲染(重新生成虚拟DOM树,对比新旧两树差异,将差异应用到真实DOM树)再回到已挂载
模板中的内容
内容
如 标题:{{title}},有动态的(双花括号),有静态的。
指令
(参考Vue.js)
1、v-bind:绑定任何元素的属性,v-bind:src 可简写为 :src="image"
2、v-for:循环数组,建议使用v-bind:key绑定稳定、唯一值,如后端来的id编号,来提升渲染效率。参考下方代码。
3、v-on:
- 绑定事件,可以是方法,或者代码
- 参数是事件名
- (v-on:click,简写为@click)
4、v-if:
5、v-show:
v-if和v-show的区别:
v-if能够控制是否生成v-node,也就间接控制了是否生成对应的dom。当v-if为true时,会生成对应的v-node,并生成对应的dom元素,当其为false时,不会生成对应的vnode,也就不会生成任何的dom元素。
v-show始终会生成vnode,也就间接导致了始终生成dom。它只是控制dom的display属性,当v-show为true时,不做任何处理,当其为false时,生成的dom的display属性为none。
使用v-if可以有效的减少树的节点和渲染量,但也会导致书的不稳定,而使用v-show时,可以保证数的稳定,但不能减少树的节点和渲染量。
当显示状态变化频繁的时候,建议使用v-show,以保持树的稳定。当显示状态变化较少时,建议使用v-if,以减少树的节点和渲染量。
6、v-slot:传递插槽内容,指定对应的插槽名称,不指定就是默认插槽。
配置中的内容
data:和界面相关的数据
methods:方法
template:配置模板
render:渲染方法,用于生成vnode
el:挂载元素的目标
computed:计算属性
props:声明组件的属性。有多种声明的形式。
1、数组
props:["url","size"]
2、对象
props:{ url:{ type:String, default:"", required:true } }
router:配置vue路由
参考代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- 模板交给--》vue --》vue将其转换为真实的dom元素-->
<div id="app">
<h1>{{ title }}</h1> <!-- 数据发生变化后,模板会重新渲染,这就是数据响应式-->
<ul>
<li v-for="( product,i ) in products" v-bind:key="product.id">
商品名称:{{ product.name }},库存:
<button v-on:click="changeStock(product,product.stock -1)">-</button>
<span>{{ product.stock ? product.stock : '售罄'}}</span>
<button v-on:click="changeStock(product,product.stock +1)">+</button>
<button v-on:click="deleteProduct(i)">删除</button>
</li>
</ul>
<p>总库存:{{ totalStock }}</p>
<img :src="image" >
</div>
<script src="./vue.min.js"></script>
<script>
var vm = new Vue({
el: '#app',//vue控制的元素或区域
data: { //页面上要使用的数据
title: '商品管理系统',
products: [
{id: 1,name: 'iphone', stock: 1},
{id : 2,name: 'xiaomi', stock: 2},
{id : 3,name: 'huawei', stock: 3}
],
image: 'https://www.baidu.com/img/bd_logo1.png'
},
computed: {
//计算属性:属性是根据已有的数据计算出来的
totalStock() {
var total = 0
for (var i = 0; i < this.products.length; i++) {
total += this.products[i].stock
}
return total
}
},
methods: {
changeStock(product, stock) {
if (stock < 0) {
product.stock = 0
return
}
product.stock = stock
},
deleteProduct(index) {
this.products.splice(index, 1)
}
//定义方法
}
})
</script>
</body>
</html>