目录
2.3.计算属性(computed) vs 侦听属性(watch)
4.1.1.在 template 元素上使用v-if条件渲染分组
4.3.v-if vs v-show( v-if 与 v-show比较)
5.1.1: 用 v-for 指令根据一组数组的选项列表进行渲染。
5.1.2: 在 v-for 块中,我们拥有对父作用域属性的完全访问权限。v-for 还支持一个可选的第二个参数为当前项的索引。
一. 模板语法:
1.插值
1.1文本
1.1.1数据绑定使用 :Mustache(胡子语法/双花括号)文本插值
注意:
双大括号会将数据解释为普通文本,而非 HTML 代码
输出html 文本 需要使用v-html指令
<p>Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
1.1.2.标签将会被替代为对应数据对象上 msg 属性的值。
1.1.3.一次性插值 : v-once 指令
当数据改变时,插值处的内容不会更新,
注意:使用 v-once 一次数据绑定 会影响该节点上其他数据
<span v-once>这个将不会改变: {{ msg }}</span>
1.2.原始 HTML
使用 v-html 指令 输出 原始html
<p>Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
注意:
直接作为 HTML——会忽略解析属性值中的数据绑定。
Mustache 语法不能作用在 HTML 特性上,遇到这种情况应该使用 v-bind 指令:
<div v-bind:id="dynamicId"></div>
1.3.使用javascript表达式
{{ number + 1 }} //可以算数计算
{{ ok ? 'YES' : 'NO' }} //三木运算
{{ message.split('').reverse().join('') }} //jsAPI 的使用 处理字符串
<div v-bind:id="'list-' + id"></div> //字符串 和 变量拼接
2.指令
指令是带有 v- 前缀的特殊属性
指令属性 的 预期值 是 单个 JavaScript 表达式(v-for 是个例外情况)
指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。
例子如下:
<div id="app">
<p v-if="seen">{{msg}}</p>
</div>
<script>
var mv = new Vue({
el:"#app",
data:{
seen:true,
msg:"现在你看到我了"
}
})
</script>
2.1.指令参数
一些指令能够接收一个“参数”,在指令名称之后以冒号表示
如:
2.1.1.v-bind 属性可以响应式的更新html属性
<a v-bind:href="url">去往天桥</a>
在这里 href 是参数, 告知v-bind 指令 将该元素的 href 属性与 表达式url 的值进行绑定
2.1.2.v-on 指令,它用于监听 DOM 事件
<a v-on:click="doSomething>...</a>
在这里参数是监听的事件名
2.1.3修饰符
修饰符 (Modifiers) 是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。
.prevent修饰符告诉 v-on指令 对于 触发事件调用event.preventDefault()事件
<form v-on:submit.prevent="onSubmit">...</form>
2.2.缩写
v- 前缀作为一种视觉提示,用来识别模板中 Vue 特定的特性
当使用 Vue.js 为现有标签添加动态行为时,v- 前缀很有帮助
在构建由 Vue.js 管理所有模板的单页面应用程序 时,v- 前缀也变得没那么重要了
2.2.1:v-bind 缩写
<--! 完整语法 -->
<a v-bind:href = "url"> 百度</a>
<--! 缩写 -->
<a :href="url"> 百度 </a>
2.2.2:v-on 缩写
<--! 完整语法 -->
<a v-on:click="doSomething"> 随便干点啥 </a>
<--! 缩写 -->
<a @:click = "doSomething"> 随便干点啥 </a>
二. 计算属性和侦听器
2.1计算属性:
解释:
对于任何复杂逻辑,都应当使用计算属性
基础例子
<div id="app">
<p>Original message: "{{ message }}"
<p>computed reverse message: "{{ reversedMessage }}</div>
<script>var vm = new Vue({
el: "#app",
data: {
message: 'hello'
},
computed: {
//计算属性的 getter
reversedMessage: function() {
return this.message.split().reverse("").join("");
}
}
});
//调用后 结果
Original message: "Hello"Computed reversed message: "olleH"
</script>
2.2计算属性缓存vs方法
计算属性是基于它们的依赖进行缓存的,计算属性只有在它的相关依赖发生改变时才会重新求值,
这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,
而不必再次执行函数
下面计算属性将不再更新
computed: {
now: function() {
return Date.now();
}
}
相比之下,每当触发重新渲染时,调用方法将总会再次执行函数
不希望有缓存,用方法来替代
2.3.计算属性(computed) vs 侦听属性(watch)
观察和响应 Vue 实例上的数据变动 使用 侦听属性(不要乱用 watch)
监听属性 watch
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function(val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function(val) {
this.fullName = this.firstName + ' ' + val
}
}
})
上面代码是命令式且重复的。将它与计算属性的版本进行比较:
2.4计算属性 computed
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function() {
return this.firstName + ' ' + this.lastName
}
}
})
2.5.计算属性的setter
计算属性默认只有 getter ,不过在需要时你也可以提供一个 setter :
<div id = "app">{{fullName}}</div>
<script>
var vm = new Vue({
el: "#app2",
data: {
firstName: "foo",
lastName: "bar"
},
computed: {
/*
fullName : function () {
return this.firstName+" "+this.lastName
}
*/
fullName: {
//getter
get: function() {
return this.firstName + " " + this.lastName
},
//setter
set: function(newVale) {
var name = newVale.split(" ");
this.firstName = name[0];
this.lastName = name[name.length - 1];
}
}
}
})
</script>
现在再运行 vm.fullName = 'John Doe' 时,setter 会被调用,vm.firstName 和 vm.lastName 也会相应地被更新。
侦听属性:
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
<script src="vue.js"></script>
<div id="app">
<p>Ask a yes/no question</p>
<input type="text" v-model="question">
<p>answer:{{answer}}</p>
</div>
<script>
let watchExampleVM = new Vue({
el: "#app",
data: {
question: "",
answer: "我不能给你一个答案,在你提问之前"
},
// 当question改变 修改 answer
watch: {
question: function(newQuestion, oldQuestion) {
this.answer = "等待输入结束...";
this.getAnswer();
}
},
methods: {
getAnswer: _.debounce(function() {
if (this.question.indexOf('?') === -1) {
this.answer = "问题必须包含'?'";
return
}
this.answer = "思考中...";
//发起 axios 请求 注意 this指向问题
var vm = this;
axios.get('https://yesno.wtf/api').then(function(response) {
vm.answer = _.capitalize(response.data.answer);
}).
catch(function(error) {
vm.answer = 'Error! Could not reach the API. ' + error;
})
},
500)
}
})
</script>
在这个示例中,
1.使用 watch 选项允许我们执行异步操作 (访问一个 API),
2.限制执行该操作的频率,
3.并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
4.除了 watch 选项之外,您还可以使用命令式的 vm.$watch API。
三. Class 与 Style 绑定
元素的 class 和 style 都是属性 在数据绑定时 用 v-bind 处理它们,只需要通过表达式计算出字符串结果即可,
将 v-bind 用于 class 和 style 时表达式结果的类型除了字符串之外,还可以是对象或数组。
3.1:绑定 HTML Class
对象语法
我们可以传给 v-bind:class 一个对象,以动态地切换 class:
四. 条件渲染
4.1.元素上使用 v-if 条件渲染分组
在 Vue 中,我们使用 v-if 指令实现条件渲染功能
<h1 v-if="ok">Yes</h1>
<!--也可以用 v-else 添加一个“else 块”:-->
<h1 v-if="ok">Yes</h1>
<h1 v-else>No</h1>
4.1.1.在 template 元素上使用v-if条件渲染分组
4.1.1.1.因为 v-if 是一个指令,所以必须将它添加到一个元素上。
4.1.1.2.v-if添加在父元素上 父元素包裹的子元素将一并渲染在页面上
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
4.1.2.v-else
使用 v-else 指令表示 v-if 的 "else块"
<div v-if="Math.random()>0.5">
now you see me
</div>
<div v-else>
now you don't
</div>
注意:v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。
4.1.3.v-else-if
v-else-if,充当 v-if 的“else-if 块”,可以连续使用
<div v-if="type == 'a'">A</div>
<div v-else-if=" type == 'b' ">B</div>
<div v-else-if=" type == 'c' ">C</div>
<div v-else>not A/B/C</div>
注意: 类似于 v-else,v-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后。
4.1.4.用 key 管理可复用的元素
Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染.
1.允许用户在不同的登录方式之间切换 并且 loginType 将不会清除用户已经输入的内容
<div>
<template v-if=" loginType == 'username' ">
<lable>UserName</lable>
<input placeholder=" Enter your username " type="text"></template>
<template v-else>
<lable>Email</lable>
<input placeholder=" Enter your email address" type="text"></template>
<button v-on:click="tabType">toggle login type</button></div>
<script>let vm = new Vue({
el: '#app',
data: {
loginType: 'username'
},
methods: {
tabType: function() {
return this.loginType = this.loginType === 'username' ? 'email': 'username'
}
}
})</script>2. toggle loginType 这两个元素是完全独立的,不要复用它们,只需添加一个具有唯一值的 key 属性即可
<div>
<template v-if=" loginType == 'username' ">
<lable>UserName</lable>
<input placeholder=" Enter your username " type="text" key="username-input"></template>
<template v-else>
<lable>Email</lable>
<input placeholder=" Enter your email address" type="text" key=" email-input "></template>
<button v-on:click="tabType">toggle login type</button></div>
<script>let vm = new Vue({
el: '#app',
data: {
loginType: 'username'
},
methods: {
tabType: function() {
return this.loginType = this.loginType === 'username' ? 'email': 'username'
}
}
})</script>
注意: <label> 元素仍然会被高效地复用,因为它们没有添加 key 属性。
4.2.v-show
用于根据条件展示元素的选项是 v-show 指令
<h1 v-show="ok">Hello!</h1>
相比不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。
v-show 只是简单地切换元素的 CSS 属性 display。
注意 : v-show 不支持 <template> 元素,也不支持 v-else。
4.3.v-if vs v-show( v-if 与 v-show比较)
4.3.1.v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
4.3.2.v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
4.3.3.v-show 不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
4.3.4: v-show 与 v-if 的适用性
v-if 有更高的切换开销,如果在运行时条件很少改变,则使用 v-if 较好。
v-show 有更高的初始渲染开销。如果需要非常频繁地切换,则使用 v-show 较好
4.4:v-if 与 v-for 一起使用
当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级。
五. 列表渲染
5.1:数组的 v-for
5.1.1: 用 v-for 指令根据一组数组的选项列表进行渲染。
v-for 指令需要使用 item in items 形式的特殊语法,items 是源数据数组并且 item 是数组元素迭代的别名。
<ul id="example">
<li v-for=" itme in items ">{{ item.message }}</li></ul>
<script>let vm = new Vue({
el: '#example',
data: {
items: [{
message: 'foo'
},
{
message: 'bar'
}]
}
})</script>
5.1.2: 在 v-for 块中,我们拥有对父作用域属性的完全访问权限。v-for 还支持一个可选的第二个参数为当前项的索引。
<ul id="example-2">
<li v-for="(item, index) in items">{{ parentMessage }} - {{ index }} - {{ item.message }}</li></ul>
<script>
var example2 = new Vue({
el: '#example-2',
data: {
parentMessage: 'Parent',
items: [{
message: 'Foo'
},
{
message: 'Bar'
}]
}
})</script>
可以用 of 替代 in 作为分隔符,因为它是最接近 JavaScript 迭代器的语法
<div v-for =" item of items> {{ item.message }} </div>
5.2:对象的 v-for
5.2.1:可以用 v-for 通过一个对象属性来迭代
<ul id="example3">
<li v-for="value in object">{{ value }}</li></ul>
<script>let vm = new Vue({
el: 'example3',
data: {
object: {
name: 'John',
age: 33,
gender: '男'
}
}
})</script>
5.2.2:可以提供第二个的参数为键名
<div v-for="(value, key) in object">
{{ key }}: {{ value }}
</div>
5.2.3:第三个参数为索引
<div v-for="(value, key, index) in object">
{{ index }}. {{ key }}: {{ value }}
</div>
注意: 在遍历对象时,是按 Object.keys() 的结果遍历,但是不能保证它的结果在不同的 JavaScript 引擎下是一致的。
5.3: key
1.当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略.
2.如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,
而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。
3.这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。
4.为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。
5.理想的 key 值是每项都有的且唯一的 id。但它的工作方式类似于一个属性,所以你需要用 v-bind 来绑定动态值 (在这里使用简写):
<div v-for="item in items" :key="item.id">
<!-- 内容 -->
</div>
5.4:数据更新与检测
5.4.1:变异方法
变异方法 会改变被这些方法调用的原始数组。
Vue 包含一组观察数组的变异方法,所以它们也将会触发视图更新。这些方法如下:
push()
打开控制台,然后用前面例子的 items 数组调用变异方法:vm2.items.push({ message: 'Baz' }) 。
pop()
vm2.items.pop({ message: 'Baz' })
shift()
vm2.itmes.shift() //把数组的第一个元素从其中删除,并返回第一个元素的值。
unshift()
vm2.itmes.unshift() //把数组的最后一个元素从其中删除 并返回最后一个元素的值
splice()
vm2.itmes.splice(1,1) //替换数组的第二个元素
sort()
//数组排序
reverse()
//数组反转
5.4.2.替换数组
1.非变异方法
filter()
concat()
slice()
2.这些不会改变原始数组,但总是返回一个新数组。
3.使用非变异方法时,可以用新数组替换旧数组:
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
4.用一个含有相同元素的数组去替换原来的数组是非常高效的操作,Vue不会丢弃现有 DOM 重新渲染整个列表。
3.注意事项
1.由于 JavaScript 的限制,Vue 不能检测以下变动的数组:
当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
当你修改数组的长度时,例如:vm.items.length = newLength
example:
var vm = new Vue({
data: {
items: ['a', 'b', 'c']
}
})
vm.items[1] = 'x' // 不是响应性的
vm.items.length = 2 // 不是响应性的
2.解决上诉问题
两种方式可以实现和 vm.items[indexOfItem] = newValue 相同的效果,同时也将触发状态更新:
1.解决利用索引直接设置一个项时 不会触发状态更新问题
1.Vue.set
Vue.set(vm.items, indexOfItem, newValue)
Vue.set(vm.items, 1, "hoa")
也可以使用 vm.$set 实例方法,该方法是全局方法 Vue.set 的一个别名
vm.$set(vm.items, indexOfItem, newValue)
2.Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
vm1.items.splice(3,1,'dddd') //该方法会返回修改之前的数组
2.解决修改数组的长度时 不会触发状态更新 可以使用 splice
vm.items.splice(newLength)
vm1.items.splice(3) //返回 被切掉的数组元素组成的新数组
5.5: 对象更改检测注意事项
5.5.1:由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除
var vm = new Vue({
data: {
a: 1
}
})
// `vm.a` 现在是响应式的
vm.b = 2
// `vm.b` 不是响应式的
5.5.2:对于已经创建的实例,Vue 不能动态添加根级别的响应式属性。
可以使用 Vue.set(object, key, value) 方法向嵌套对象添加响应式属性。
var vm = new Vue({
data : {
userProfile:{
name : 'Anika'
}
}
})
添加一个新的 age 属性到嵌套的 userProfile 对象:
vm.$set(vm.userProfile,'age',27)
5.5.3:为已有对象赋予多个新属性
使用 Object.assign() 或 _.extend() 添加响应式属性
vm.userProfile = Object.assign({}, vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
5.6显示过滤/排序结果
1.显示一个数组的过滤或排序副本,而不实际改变或重置原始数据。(可以创建返回过滤或排序数组的计算属性)
<ul id="a">
<li v-for="n in evenNumbers">{{n}}</li></ul>
<script>let vm = new Vue({
el: '#a',
data: {
numbers: [1, 2, 3, 4, 5]
},
computed: {
evenNumbers: function() {
return this.numbers.filter(function(number) {
return number % 2 === 0;
})
}
}
})</script>
2.在计算属性不适用的情况下可以 使用methods方法 ex:如下实例
<ul id="b">
<li v-for="n of even(numbers)">{{n}}</li></ul>
<script>let vm2 = new Vue({
el: '#b',
data: {
numbers: [1, 2, 3, 4, 5]
},
methods: {
even: function(numbers) {
return numbers.filter(function(numbers) {
return numbers % 2 === 0
})
}
}
})</script>
5.7 一段取值范围的 v-for
v-for 也可以取整数 在这种情况下,它将重复多次模板
<div id="a">
<span v-for="n in 10">{{n}}</span></div>
<script>
let vm = new Vue({
el: '#a',
data: {
10 : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
}
})
</script>
5.8:v-for on a <template>
类似于 v-if,你也可以利用带有 v-for 的 <template> 渲染多个元素。
<style>.active{ color:red; font-size: 20px; }</style>
<ul id="a">
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li v-bind:class="isActive">dingidng</li></template>
</ul>
<script>let vm = new Vue({
el: '#a',
data: {
isActive: 'active',
items: [{
msg: '你好我是李华'
},
{
msg: '太煽情了'
},
{
msg: '东东,你好'
}]
}
})</script>
5.9:v-优先for with v-if
当 v-for 与 v-if 处于同一个节点时 v-for 的优先级比 v-if 的优先级要高
5.10: 一个组件的 v-for
1. 在自定义组件里,你可以像任何普通元素一样用 v-for
<my-component v-for="item in items" :key="item.id"></my-component>
2. 在 Vue.js 2.2.0+ 的版本里,在组件中使用 v-for 时,key 现在是必须的。
3. 任何数据都不会被自动传递到组件里,因为组件有自己独立的作用域。为了把迭代数据传递到组件里,我们要用 props
六. 事件处理
6.1事件监听
可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。
<div id="a">
<button v-on:click="count+=1">Add+1</button>
<p>The button above has been clicked {{ count }} times.</p>
</div>
<script>let vm = new Vue({
el: '#a',
data: {
count: 0
}
});</script>
6.2: 事件处理方法
v-on 还可以接收一个需要调用的方法名称。
<div id="a">
<button v-on:click="greet">Greet</button></div>
<script>let vm = new Vue({
el: '#a',
data: {
name: 'vue.js'
},
methods: {
greet: function(event) {
alert("hello" + " " + this.name + " " + '!') if (event) { //当 点击事件触发时 会弹出事件名称 (在控制台直接调用该函数不会触发此事件)
alert(event.target.tagName);
}
}
}
})
//可以在控制台直接调用 : vm.greet()
//如果在控制台直接调用不会触发点击事件 所以不会弹出事件名称
</script>
6.3: 内联处理器中的方法
除了直接绑定到一个方法,也可以在内联 JavaScript 语句中调用方法:
6.4:事件修饰符
在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。
方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。
Vue.js 为 v-on 提供了事件修饰符 修饰符是由点开头的指令后缀来表示的。
.stop
.prevent
.capture
.self
.once
案例:
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即元素自身触发的事件先在此处处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
<!-- 点击事件将只会触发一次 -->
<a v-on:click.once="doThis"></a>
Vue 还对应 addEventListener 中的 passive 选项提供了 .passive 修饰符。
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成 -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>
这个 .passive 修饰符尤其能够提升移动端的性能。
注意:
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。
因此,用 v-on:click.prevent.self 会阻止所有的点击,而 v-on:click.self.prevent 只会阻止对元素自身的点击。
.once 修饰符还能被用到自定义的组件事件上,不像其它只能对原生的 DOM 事件起作用的修饰符。
不要把 .passive 和 .prevent 一起使用,因为 .prevent 将会被忽略,同时浏览器可能会向你展示一个警告。请记住,.passive 会告诉浏览器你不想阻止事件的默认行为
(5) 按键修饰符
Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:
<!-- 只有在 `keyCode` 是 13 时调用 `vm.submit()` -->
<input v-on:keyup.13="submit">
Vue 为最常用的按键提供了别名:
<!-- 同上 -->
<input v-on:keyup.enter="submit">
<!-- 缩写语法 -->
<input @keyup.enter="submit">
全部的按键别名:
.enter
.tab
.delete (捕获“删除”和“退格”键)
.esc
.space
.up
.down
.left
.right
可以通过全局 config.keyCodes 对象自定义按键修饰符别名:
// 可以使用 `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112
七. 表单输入绑定
你可以用 v-model 指令在表单 <input> 及 <textarea> 元素上创建双向数据绑定。
但 v-model 本质上不过是语法糖。v-model负责监听用户的输入事件以更新数据
注意:
v-model 会忽略所有表单元素的 value、checked、selected 的初始值而总是将 Vue 实例的数据作为数据来源。
你应该在 data 选项中声明初始值。
基础用法:
7.1: 文本
<div id="a">
<input type="text" v-model="msg" placeholder="enter message"></br>
<span>message:{{msg}}{{foo}}</span></div>
<script>let vm = new Vue({
el: '#a',
data: {
msg: ''
},
computed: {
foo: function() {
console.log(this.msg)
}
}
})</script>
7.2:多行文本
<div id="ab">
<span>Multline Message is:</span>
<p style="white-space: pre-line">{{message}}</p>
<textarea name="" id="" cols="30" rows="10" v-model="message"></textarea>
</div>
<script>let vm2 = new Vue({
el: '#ab',
data: {
message: ''
}
})</script>
7.3:多个复选框,绑定到同一个数组
<div id="c">
<input type="checkbox" id="jack" value="jack" v-model="checkNames">
<label for="jack">jack</label>
<input type="checkbox" id="Wilson" value="Wilson" v-model="checkNames">
<label for="Wilson">Wilson</label>
<input type="checkbox" id="lili" value="lili" v-model="checkNames">
<label for="lili">lili</label>
<br>
<span>checkNames:{{checkNames}}</span></div>
<script>let vm3 = new Vue({
el: '#c',
data: {
checkNames: []
}
})</script>
7.4单选按钮
<div id="d">
<p>选择性别</p>
<input type="radio" id="gender" value="woman" v-model="gender">
<label for="gender">woman</label>
<input type="radio" id="gender" value="man" v-model="gender">
<label for="gender">man</label>
<br>
<span>gender : {{gender}}</span></div>
<script>let vm4 = new Vue({
el: '#d',
data: {
gender: ''
}
})</script>
7.5 用 v-for 渲染的动态选项:
<div id="a">
<select v-model="selected">
<option v-for="option in options" v-bind:value="option.value">{{option.text}}</option></select>
<span>select:{{ selected }}</span></div>
<script>let vm = new Vue({
el: '#a',
data: {
selected: 'A',
//次数据在data 内部
options: [{
text: 'one',
value: 'A'
},
{
text: 'two',
value: 'B'
},
{
text: 'three',
value: 'C'
}]
}
})</script>
八. 组件
组件可以扩展 HTML 元素,封装可重用的代码。
组件也可以表现为用 is 特性进行了扩展的原生 HTML 元素
所有的 Vue 组件同时也都是 Vue 的实例,所以可接受相同的选项对象 (除了一些根级特有的选项) 并提供相同的生命周期钩子
注意: 在初始化根实例之前注册组件
8.1:使用组件
8.1.1注册全局组件
<div id="app">
<my-component></my-component>
</div>
<script>Vue.component('my-component', {
template: '<div> this is all component </div>'
});
let vm = new Vue({
el: '#app'
})</script>
8.1.2注册局部组件
通过某个 Vue 实例/组件的实例选项 components 注册仅在其作用域中可用的组件
<div id="a">
<my-component></my-component>
</div>
<script>let child = { //声明一个 对象 在对象中写入组件
template: '<div> this is a component</div>'
};
let vm = new Vue({
el: '#a',
components: { //组件注册在 component 选项中
'my-component': child //此时组件名称 需要加 引号 切记
}
})</script>
这种封装也适用于其它可注册的 Vue 功能,比如指令
8.1.3: DOM 模板解析注意事项
在特殊的标签当中 使用 is 特性
8.1.4 data 必须是函数
在组件实例中 data 必须是一个函数(不可以是对象)
示例:
Vue.component('my-component', {
template: '<span>{{ message }}</span>',
data: {
message: 'hello'
}
})
此时data是一个对象会导致vue停止运行 (控制台发出警告)※在vue组件实例中data选项必须是函数
<div id="a">
<my-component></my-component>
<my-component></my-component>
<my-component></my-component>
</div >
<script >
//let data = { count:0 }
Vue.component('my-component', {
template: '<button v-on:click="count +=1 ">{{ count }}</button>',
/*data : function () {
return data
}*/
//问 题 : 这种方法将导致 三个 组件同时引用一个对象 当对其中任何一个组件执行 递增操作其他组件随之也会更改
data: function() { //解决办法 : 为每个组件返回全新的数据对象来修复这个问题
return {
count: 0
}
}
});
let vm = new Vue({
el: '#a',
}) < /script>
8.1.5组件组合
在 Vue 中,父子组件的关系可以总结为 prop 向下传递,事件向上传递
父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息
8.2:Prop
8.2.1:使用 Prop 传递数据
父组件的数据需要通过 prop 才能下发到子组件中.
子组件要显式地用 props 选项声明它预期的数据
js:
Vue.component("my-component", {
props: ['message'],
template: '<div>{{message}}</div>
})
new Vue({
el: '#app ',
})'
html:
<div id="app">
<my-component message='hello'></my-component>
</div>
8.2.2:命名规范
HTML 特性是不区分大小写的,当使用的不是字符串模板时,
驼峰式命名 (camelCase) 的 prop 需要转换为相对应的 短横线分隔式命名 (kebab-case)
Vue.component('child', {
// 在 JavaScript 中使用 camelCase
props: ['myMessage'],
template: '<span>{{ myMessage }}</span>'
})
<!-- 在 HTML 中使用 kebab-case -->
<child my-message="hello!"></child>
8.2.3.动态 Prop
用 v-bind 来动态地将 prop 绑定到父组件的数据,每当父组件的数据变化时,该变化也会传导给子组件
<div id="app">
<input type="text" v-model="parentMsg">
<br>
<child-comp v-bind:child-msg="parentMsg"></child-comp>
</div>
<script>Vue.component('child-comp', {
props: ['childMsg'],
template: '<span>{{childMsg}}</span>'
});
new Vue({
el: '#app',
data: {
parentMsg: 'hello World'
}
})</script>
把一个 prop 的所有对象进行传递 可以通过 v-bind 而不是 v-bind:prop-name
例如: 有一个todo 对象
todo: {
text: 'Learn Vue',
isComplete: false
}
然后:
<todo-item v-bind="todo"></todo-item>
8.2.4:字面量语法 vs 动态语法
错误 : 使用字面量语法传递数值
<!-- 传递了一个字符串 "1" -->
<comp some-prop="1"></comp>
原因 : 因为它是一个字面量 prop,它的值是字符串 "1" 而不是一个数值
正确 : 如果想传递一个真正的 JavaScript 数值,则需要使用 v-bind,从而让它的值被当作 JavaScript 表达式计算
<!-- 传递真正的数值 -->
<comp v-bind:some-prop="1"></comp>
8.2.5:单项数据流
Prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是反过来不会(防止子组件无意间修改了父组件的状态,造成误解)
每次父组件更新时,子组件的所有 prop 都会更新为最新值,不应该在子组件内部改变 prop,如果修改了prop vue 会发出警告
问题 : 在两种情况下,我们很容易忍不住想去修改 prop 中数据:
1.Prop 作为初始值传入后,子组件想把它当作局部数据来用;
2.Prop 作为原始数据传入,由子组件处理成其它数据输出。
解决办法:
第一个问题:
定义一个局部变量,并用 prop 的值初始化它:
props: ['initialCounter'],
data: function () {
return { counter: this.initialCounter }
}
第二个问题:
定义一个计算属性,处理 prop 的值并返回:
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
注意: 注意在 JavaScript 中对象和数组是引用类型,指向同一个内存空间,如果 prop 是一个对象或数组,在子组件内部改变它会影响父组件的状态。
8.2.6:Prop 验证
为组件的 prop 指定验证规则。如果传入的数据不符合要求,Vue 会发出警告。
要指定验证规则,需要用对象的形式来定义 prop,而不能用字符串数组
Vue.component('example', {
props: {
// 基础类型检测 (`null` 指允许任何类型)
propA: Number,
// 可能是多种类型
propB: [String, Number],
// 必传且是字符串
propC: {
type: String,
required: true
},
// 数值且有默认值
propD: {
type: Number,
default:
100
},
// 数组/对象的默认值应当由一个工厂函数返回
propE: {
type: Object,
default:
function() {
return {
message:
'hello'
}
}
},
// 自定义验证函数
propF: {
validator: function(value) {
return value > 10
}
}
}
})
type 可以是下面原生构造器:
String
Number
Boolean
Function
Object
Array
Symbol
8.2.7:非 Prop 特性
所谓非 prop 特性,就是指它可以直接传入组件,而不需要定义相应的 prop。
8.3:子组件与父组件通信
8.3.1.使用 v-on 绑定自定义事件
父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
不能用 $on 监听子组件释放的事件,而必须在模板里直接用 v-on 绑定,
<div id="count-event-example">
<p>{{ total }}</p>
<!-- 此时 父组件 使用 v-on 监听子组件触发事件 -->
<button-counter v-on:increment = "incrementTotal"></button-counter>
<!-- 3. 接收到触发 increment 指令 调用 incrementTotal 方法
<button-counter v-on:increment = "incrementTotal"></button-counter>
</div>
<script>
Vue.component('button-counter',{
template:'<button v-on:click="incrementCounter">{{ counter }}</button>', //1.当点击按钮 时 调用 incrementCouture 方法
data:function () {
return {
counter: 0
}
},
methods:{
incrementCounter:function () { //2.调用次方法时
this.counter += 1; //2.1把 data 中的 counter+1
this.$emit('increment'); //2.2触发 increment 事件
}
}
});
new Vue({
el: '#count-event-example',
data:{
total:0
},
methods: {
incrementTotal: function () { //4. 调用 incrementTotal 方法
this.total += 1 //4.1 将 total 自增+1
}
}
})
</script>
8.3.2:使用载荷数据
<div id="message-event-example">
<p v-for="msg in message">{{msg}}</p>
<button-message v-on:message="handleMessage"></button-message>
</div>
<script>
Vue.component('button-message',{
template:'<div>' +
'<input type="text" v-model="message">' +
'<button v-on:click="handleSendMsg">send</button>' +
'</div>',
data:function () {
return {
message:'test message'
}
},
methods:{
handleSendMsg:function () {
this.$emit('message',{message:this.message})
}
}
});
new Vue({
el: '#message-event-example',
data: {
message:[]
},
methods:{
handleMessage:function (payload) {
this.message.push(payload.message);
}
}
})
</script>