Vue的基础知识(二)
本章将继续和大家分享Vue的一些基础知识。话不多说,下面我们直接上代码:
本文内容大部分摘自Vue的官网 :https://v2.cn.vuejs.org/v2/guide/
一、计算属性
示例如下:
<! 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 > Vue中的计算属性 </ title > < script src ="/lib/vue.js" ></ script > </ head > < body > < div id ="app" > < div desc ="计算属性" > < p > Original message: "{{ message }}" </ p > < p > Computed reversed message: "{{ reversedMessage }}" </ p > </ div > </ div > < script > var vm = new Vue({
el: ' #app ' , // 挂载点 data: {
message: ' Hello ' },
computed: { // 计算属性的 getter reversedMessage: function () { // `this` 指向 vm 实例 return this .message.split( '' ).reverse().join( '' );
}
},
methods: { // 普通方法 reversedMessageMethod: function () { /* 1、我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。
然而,不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。
这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。
2、相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。
3、我们为什么需要缓存?假设我们有一个性能开销比较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。
然后我们可能有其他的计算属性依赖于 A。如果没有缓存,我们将不可避免的多次执行 A 的 getter!如果你不希望有缓存,请用方法来替代。 */ return this .message.split( '' ).reverse().join( '' );
}
}
}); </ script > </ body > </ html >
结果:
Original message: "Hello"
Computed reversed message: "olleH"
计算属性默认只有 getter,不过在需要时你也可以提供一个 setter:
// ...
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
// ...
你可以像绑定普通 property 一样在模板中绑定计算属性。Vue 知道 vm.reversedMessage 依赖于 vm.message,因此当 vm.message 发生改变时,所有依赖 vm.reversedMessage 的绑定也会更新。而且最妙的是我们已经以声明的方式创建了这种依赖关系:计算属性的 getter 函数是没有副作用 (side effect) 的,这使它更易于测试和理解。
计算属性缓存 vs 方法:我们可以将同一函数定义为一个方法而不是一个计算属性。两种方式的最终结果确实是完全相同的。然而, 不同的是计算属性是基于它们的响应式依赖进行缓存的 。只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。
我们为什么需要缓存?假设我们有一个性能开销比较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于 A。如果没有缓存,我们将不可避免的多次执行 A 的 getter!如果你不希望有缓存,请用方法来替代。
二、侦听属性
Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
示例如下:
<! 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 > Vue中的侦听器 </ title > < script src ="/lib/vue.js" ></ script > < script src ="/lib/axios.js" ></ script > < script src ="/lib/lodash.js" ></ script > </ head > < body > < div id ="app" > < div desc ="侦听属性" > < p > 请输入您的问题: < input v-model ="question" > </ p > < p > {{ answer }} </ p > </ div > </ div > < script > var vm = new Vue({
el: ' #app ' , // 挂载点 data: {
question: '' ,
answer: ' 在您提出问题之前,我不能给您答案! ' },
watch: { // 如果 `question` 发生改变,这个函数就会运行 question: function (newQuestion, oldQuestion) { var _this = this ;
_this.answer = ' 正在等待您停止输入... ' _this.debouncedGetAnswer();
}
},
created: function () { // `_.debounce` 是一个通过 Lodash 限制操作频率的函数。 // 在这个例子中,我们希望限制访问 接口 的频率 // AJAX 请求直到用户输入完毕才会发出。想要了解更多关于 // `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识, // 请参考:https://lodash.com/docs#debounce var _this = this ;
_this.debouncedGetAnswer = _.debounce(_this.getAnswer, 1500 ); // debouncedGetAnswer 方法名可自定义 },
methods: {
getAnswer: function () { var _this = this ; if (_this.question.indexOf( ' ? ' ) === - 1 ) {
_this.answer = ' 问题通常包含问号! ' ; return ;
}
_this.answer = ' 数据获取中... ' ;
axios.get( ' https://autumnfish.cn/api/joke ' )
.then( function (response) {
_this.answer = response.data;
})
. catch ( function (error) {
_this.answer = ' 请求接口异常: ' + error;
});
}
}
}); </ script > </ body > </ html >
在这个示例中,使用 watch 选项允许我们执行异步操作 (访问一个 API),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
Lodash下载地址 :https://github.com/lodash/lodash/tree/4.17.21
三、Class 与 Style 绑定
示例如下:
<! 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 > Class与Style绑定 </ title > < script src ="/lib/vue.js" ></ script > </ head > < body > < div id ="app" > < div desc ="对象语法" > <!-- active 这个 class 存在与否将取决于数据 property isActive 的 真值。 --> <!-- 你可以在对象中传入更多字段来动态切换多个 class。此外,v-bind:class 指令也可以与普通的 class attribute 共存。 --> <!-- 当 isActive 或者 hasError 变化时,class 列表将相应地更新。例如,如果 hasError 的值为 true,class 列表将变为 "static active text-danger"。 --> < div class ="static" v-bind:class ="{ active: isActive, 'text-danger': hasError }" ></ div > <!-- 绑定的数据对象不必内联定义在模板里 --> < div v-bind:class ="classObject" ></ div > <!-- 我们也可以在这里绑定一个返回对象的计算属性 --> < div v-bind:class ="classObjectComputed" ></ div > </ div > < div desc ="数组语法" > <!-- 我们可以把一个数组传给 v-bind:class,以应用一个 class 列表 --> < div v-bind:class ="[activeClass, errorClass]" ></ div > <!-- 如果你也想根据条件切换列表中的 class,可以用三元表达式 --> <!-- 这样写将始终添加 errorClass,但是只有在 isActive 是 真 时才添加 activeClass。 --> < div v-bind:class ="[isActive ? activeClass : '', errorClass]" ></ div > <!-- 不过,当有多个条件 class 时这样写有些繁琐,所以在数组语法中也可以使用对象语法 --> < div v-bind:class ="[{ active: isActive }, errorClass]" ></ div > </ div > < div desc ="绑定内联样式" > <!-- v-bind:style 的对象语法十分直观——看着非常像 CSS,但其实是一个 JavaScript 对象。 --> <!-- CSS property 名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名 --> < div v-bind:style ="{ color: activeColor, fontSize: fontSize + 'px' }" ></ div > <!-- 直接绑定到一个样式对象通常更好,这会让模板更清晰 --> <!-- 同样的,对象语法常常结合返回对象的计算属性使用 --> < div v-bind:style ="styleObject" ></ div > <!-- v-bind:style 的数组语法可以将多个样式对象应用到同一个元素上: --> < div v-bind:style ="[baseStyles, overridingStyles]" ></ div > </ div > </ div > < script > var vm = new Vue({
el: ' #app ' , // 挂载点 data: {
isActive: true ,
hasError: false ,
classObject: {
active: true , ' text-danger ' : false },
activeClass: ' active ' ,
errorClass: ' text-danger ' ,
activeColor: ' red ' ,
fontSize: 30 ,
styleObject: {
color: ' red ' ,
fontSize: ' 13px ' },
baseStyles: {
color: ' black ' ,
fontSize: ' 13px ' },
overridingStyles: { ' text-align ' : ' center ' }
},
computed: {
classObjectComputed: function () { return {
active: this .isActive && ! this .hasError, ' text-danger ' : this .hasError
}
}
}
}); </ script > </ body > </ html >
渲染的结果如下:
< div id ="app" > < div desc ="对象语法" > < div class ="static active" ></ div > < div class ="active" ></ div > < div class ="active" ></ div > </ div > < div desc ="数组语法" > < div class ="active text-danger" ></ div > < div class ="active text-danger" ></ div > < div class ="active text-danger" ></ div > </ div > < div desc ="绑定内联样式" > < div style ="color: red; font-size: 30px;" ></ div > < div style ="color: red; font-size: 13px;" ></ div > < div style ="color: black; font-size: 13px; text-align: center;" ></ div > </ div > </ div >
四、条件渲染
示例如下:
<! 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 > Vue中的条件渲染 </ title >
< script src ="lib/vue.js" ></ script >
</ head >< body >
< div id ="app" >
< div desc ="条件渲染" >
<!-- v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 true 值的时候被渲染。 -->
<!-- 可以把一个 <template> 元素当做不可见的包裹元素,并在上面使用 v-if。最终的渲染结果将不包含 <template> 元素。 -->
< template v-if ="loginType === 'username'" >
< label > Username </ label >
< input placeholder ="Enter your username" key ="username-input" >
</ template >
< template v-else-if ="loginType === 'telephone'" >
< label > Telephone </ label >
< input placeholder ="Enter your telephone" key ="telephone-input" >
</ template >
< template v-else >
< label > Email </ label >
< input placeholder ="Enter your email address" key ="email-input" >
</ template ><!-- v-show 只是简单地切换元素的 CSS property display。 -->
< h1 v-show ="isShow" > Hello! </ h1 >
</ div >
</ div >< script >
// 一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。
//