Vue核心
Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统:
<div id="app">
{{ message }}
</div>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
//在浏览器中通过vm.message=“Hello Vue”发现视图改变了,内部是通过mvvm模式
}
})
mvvm模式
vue中采用mvvm模式
m:model 数据模型层
v:view 视图层
vm:viewModel vue的实例
view <===> vm <===> model
注意:model层与view层没有必然的联系了,都是靠vm将两者进行双向数据绑定
当model层数据改变了,viewmodel就知道数据发生变化了,更新view层,反之亦然。
列表渲染v-for
v-for 指令基于一个数组来渲染一个列表。
v-for 指令需要使用 item in items 形式的特殊语法,
其中 items 是源数据数组,
而 item 则是被迭代的数组元素的别名。
<div id="app">
<ul>
<li v-for="item in arr">{{item}}</li>
<li v-for="it of arr">{{it}}</li>
</ul>
</div>
<script src="./base/vue.js"></script>
<script>
new Vue({
el:"#app",
data:{
arr:["苹果","机子","你好","不好"]
}
})
</script>
同样v-for不仅更可以遍历数组还可以遍历json对象
// v-for = "(value,key,index) in object"
// value:代表所遍历的value
// key : 代表所遍历的键
// index:代表下标
// object:代表源json对象
<div id="app">
<ul>
<li v-for="item,key in water">{{key}}:{{item}}</li>
</ul>
</div>
<script src="./base/vue.js"></script>
<script>
new Vue({
el:"#app",
data:{
water:{
name:"老三矿泉水",
age:"百年历史",
money:"2元"
}
}
})
</script>
v-for中的key
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key attribute:
为什么v-for指令当中添加key? (key值是唯一的,尽量不要用index下标,除非你知道下标是不变的)
//虚拟dom对比的时候,添加元素、删除元素的时候 key 提高对比效率
//因为如果没有加key,内部插入新的元素,后面的元素都会经历卸载与重新装载的过程,效率太低了
//添加key之后,内部本着key值相同,dom节点复用原则。
同样关于key
key
key 的特殊 attribute 主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用 key 时,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。
有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。
最常见的用例是结合 v-for:
<ul>
<li v-for="item in items" :key="item.id">...</li>
</ul>
它也可以用于强制替换元素/组件而不是重复使用它。当你遇到如下场景时它可能会很有用:
1.完整地触发组件的生命周期钩子
2.触发过渡
例如:
<transition>
<span :key="text">{{ text }}</span>
</transition>
当 text 发生改变时, 总是会被替换而不是被修改,因此会触发过渡。
template标签
- 一、html5中的template标签
html中的template标签中的内容在页面中不会显示。但是在后台查看页面DOM结构存在template标签。这是因为template标签天生不可见,它设置了display:none;属性。
<!--当前页面只显示"我是自定义表现abc"这个内容,不显示"我是template",这是因为template标签天生不可见-->
<template><div>我是template</div></template>
<abc>我是自定义表现abc</abc>
- 二、template标签操作的属性和方法
content属性:在js中template标签对应的dom对象存在content属性,对应的属性值是一个dom节点,节点的nodeName是#document-fragment。通过该属性可以获取template标签中的内容,template对象.content可以调用getElementById、querySelector、querySelectorAll方法来获取里面的子节点。
innerHTML:可以获取template标签中的html。
<template id="tem">
<div id="div1">我是template</div>
<div>我是template</div>
</template>
<script>
let o = document.getElementById("tem");
console.log(o.content.nodeName);//#document-fragment
console.log(o.content.querySelectorAll("div"));//NodeList(2) [div#div1, div]。得到一个类数组
console.log(o.content.getElementById("div1"));//<div id="div1">我是template</div>
console.log(o.innerHTML);//'<div id="div1">我是template</div><div>我是template</div>'
</script>
- 三、vue中的template
1、template标签在vue实例绑定的元素内部
它是可以显示template标签中的内容,但是查看后台的dom结构不存在template标签。如果template标签不放在vue实例绑定的元素内部默认里面的内容不能显示在页面上,但是查看后台dom结构存在template标签。
<div id="app">
<!--此处的template标签中的内容显示并且在dom中不存在template标签-->
<template>
<div>我是template</div>
<div>我是template</div>
</template>
</div>
<!--此处的template标签中的内容在页面中不显示,但是在dom结构存在该标签及内部结构-->
<template id="tem">
<div id="div1">我是template</div>
<div>我是template</div>
</template>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
});
</script>
注意: vue实例绑定的元素内部的template标签不支持v-show指令,即v-show="false"对template标签来说不起作用。但是此时的template标签支持v-if、v-else-if、v-else、v-for这些指令。
<div id="app">
<template v-if="true">
<!--此时template标签中的内容显示在页面上,但是看dom结构没有template标签-->
<div>我是template</div>
<div>我是template</div>
</template>
<div v-if="true">
<!--此时页面上显示div标签中的内容,并且看dom结构存在最外面的div标签-->
<div>我是template</div>
<div>我是template</div>
</div>
<!--此处会输出6个‘我是template’并且dom结构中不存在template标签-->
<template v-for="a in 3">
<div>我是template</div>
<div>我是template</div>
</template>
</div>
<script src="node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el: "#app",
});
</script>
2、vue实例中的template属性
将实例中template属性值进行编译,并将编译后的dom替换掉vue实例绑定的元素,如果该vue实例绑定的元素中存在内容,这些内容会直接被覆盖。
特点:
1)如果vue实例中有template属性,会将该属性值进行编译,将编译后的虚拟dom直接替换掉vue实例绑定的元素(即el绑定的那个元素);
2)template属性中的dom结构只能有一个根元素,如果有多个根元素需要使用v-if、v-else、v-else-if设置成只显示其中一个根元素;
3)在该属性对应的属性值中可以使用vue实例data、methods中定义的数据。
<!--此处页面显示hello-->
<div id="app"></div>
<!--此处template标签必须在vue绑定的元素外面定义,并且在页面中不显示下面的template标签中的内容-->
<template id="first">
<div v-if="flag">{{msg}}<div>
<div v-else>111<div>
</template>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el:"#app",
data:{
msg:"hello",
flag:true
},
template:"#first"//通过该属性可以将自定义的template属性中的内容全部替换app的内容,并且会覆盖里面原有的内容,并且在查看dom结构时没有template标签
});
</script>
上面的例子中html中的template标签可以变成自定的标签,如下。但是下面这种方式也可以将<abc></abc>
标签中的内容替换掉app元素,但是<abc></abc>
标签中的内容也会显示在页面上。所以此处利用template标签来定义vue实例中需要设置的template属性。
<abc id="first">
<div v-if="flag">{{msg}}<div>
<div v-else>111<div>
</abc>
上面的实例还可以写成下面的形式
<!--此处页面显示hello-->
<div id="app"></div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
let vm = new Vue({
el:"#app",
data:{
msg:"hello",
flag:true
},
template:"<div v-if='flag'>{{msg}}</div><div v-else>123</div>"//模板中只能有一个根元素,如果有多个需要使用v-if、v-else、v-else-if来选择显示哪一个
});
</script>
vue中的数组
Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。
这些被包裹过的方法包括:
push() 数组的后面插入元素
pop() 从数组的后面删除一个元素
shift() 从数组的前面删除一个元素
unshift() 从数组的前面插入一个元素
splice() 数组的剪贴、插入、删除等操作
sort() 数组的排序
reverse() 数组的反转
**注意**:
由于 JavaScript 的限制,Vue 不能检测数组和对象的变化
1. vm.arr[0] = 10 发现数据改变了,但是视图却没有发生变化!
1)vm.arr.splice(0,1,10)
2) Vue.set(vm.arr,0,10)
2. vm.arr.length = 2
vm.arr.splice(2)
3. vm.user.age = 18 发现视图没有任何改变
Vue.set(vm.user,"age",18)
之前的name被vue实例进行挂载了,所以会动态的为其添加get与set方法,数据劫持。数据改变 ==> set ==> watcher ==> 视图更新
但是后续vm.user.age = 18 这个属性,只是简单的数据改变,
没有进行内部的数据劫持,去进行动态的添加get与set,数据改变了,但是视图不会更新。
怎么让其变成响应式的呢? vue当中提供了一个全局的api方法 Vue.set()
就可以为动态添加的数据也会被vue管理,双向数据绑定了。
v-on
缩写:@
预期:Function | Inline Statement | Object
参数:event
修饰符:(vue中提供事件修饰符)
.stop - 调用 event.stopPropagation()。阻止事件冒泡
.prevent - 调用 event.preventDefault()。阻止事件默认行为
.capture - 添加事件侦听器时使用 capture 模式。
.self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。
.{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
.native - 监听组件根元素的原生事件。
.once - 只触发一次回调。
.enter 提供了键盘修饰符
.left - (2.2.0) 只当点击鼠标左键时触发。
.right - (2.2.0) 只当点击鼠标右键时触发。
.middle - (2.2.0) 只当点击鼠标中键时触发。
.passive - (2.3.0) 以 { passive: true } 模式添加侦听器
v-model
//请你说一下 v-model底层原理实现?
//绑定了value属性与监听了input事件
//详细来说是通过v-bind绑定value属性 通过v-on绑定input属性
//v-model常用修饰符有哪些?
//1.v-model.lazy 默认是实时更新,如果加了lazy修饰符,只有失去焦点的时候,内部才会更新
//2.v-model.number 这个值无法被parseFloat解析的时候原样输出,否则转换
//3.v-model.trim 去掉前后空格
//注意: v-model指令只能用在组件或者表单控件中
// 你可以用 v-model 指令在表单 <input>、<textarea> 及 <select> 元素上创建双向数据绑定
案例
<div id="app">
<p>{{mgs}}</p>
<p><input type="text" v-model="mgs"></p>
</div>
<script src="./base/vue.js"></script>
<script>
new Vue({
el:"#app",
data:{
mgs:"<h1>你好烦哈回复哈</h1>"
}
})
</script>
v-bind
动态地绑定一个或多个 attribute,或一个组件 prop 到表达式。
v-bind
缩写::
预期:any (with argument) | Object (without argument)
参数:attrOrProp (optional)
修饰符:
.prop - 作为一个 DOM property 绑定而不是作为 attribute 绑定。(差别在哪里?)
.camel - (2.1.0+) 将 kebab-case attribute 名转换为 camelCase。(从 2.1.0 开始支持)
.sync (2.3.0+) 语法糖,会扩展成一个更新父组件绑定值的 v-on 侦听器。