vue条件语句、循环语句、计算属性、侦听器监听属性
因为 v-if 和v-for是一个指令,所以必须将它添加到一个元素上。但是如果想切换多个元素呢?此时可以把一个 <template> 元素当做不可见的包裹元素,并在上面使用 v-if。最终的渲染结果将不包含 <template> 元素。
1.条件语句
vue中条件语句类似于JS语法的if-else语句。当然可以用!表示非。v-else 、v-else-if 必须跟在 v-if 或者 v-else-if之后。
例如:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script src="js/vue.min.js"></script> </head> <body> <h1>if 语句</h1> <div id="app"> <p v-if="seen">现在你看到我了</p> <p v-if="!seen">现在你看不到到我了</p> <template v-if="ok"> <h6>vue教程</h6> </template> </div> <script> var appIf = new Vue({ el: '#app', data: { seen: false, ok: true } }) </script> <h1>if - else 语句</h1> <div id="app2"> <div v-if="Math.random() > 0.5"> 大于0.5 </div> <div v-else> 小于等于0.5 </div> </div> <script> var app2 = new Vue({ el: '#app2' }) </script> <h1>if - else if - else 语句</h1> <div id="app3"> <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> </div> <script> var app3 = new Vue({ el: '#app3', data: { type: 'C' } }) </script> </body> </html>
结果:
补充:我们也可以使用 v-show 指令来根据条件展示元素:
<h1>if 语句</h1> <div id="app"> <h1 v-show="seen">Hello!</h1> </div> <script> var appIf = new Vue({ el: '#app', data: { seen: false, ok: true } }) </script>
结果:
补充:v-if和v-show的区别
v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
补充:v-if判断数组的长度:
<div v-if="remarks.length > 0"> <div v-for="(remark,index) in remarks" style="margin-top: 20px;" :key="index"> <span>第{{ index + 1 }}楼</span> <span style="margin-left: 5px;">{{ remark.creator }}</span> <span style="margin-left: 5px;">{{ remark.createtimeStr}}</span> <br /> <span>{{ remark.content }}</span> </div> </div> <div v-else> 暂无评论 </div>
2.循环语句
循环使用 v-for 指令。v-for 指令需要以 site in sites 形式的特殊语法, sites 是源数据数组并且 site 是数组元素迭代的别名。
v-for用法1和模板中v-for用法最常用,而且模板元素template在渲染页面之后不会呈现。
例如:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script src="js/vue.min.js"></script> </head> <body> <h4>v-for用法1</h4> <div id="app1"> <ol> <li v-for="site in sites"> {{ site.name }} </li> </ol> </div> <script> var app1 = new Vue({ el: '#app1', data: { sites: [{ name: 'Runoob' }, { name: 'Google' } ] } }) </script> <h4>模板中v-for</h4> <div id="app2"> <ol> <template v-for="site in sites"> <li>{{ site.name }}</li> </template> </ol> </div> <script> var app2 = new Vue({ el: '#app2', data: { sites: [{ name: 'Runoob' }, { name: 'Google' } ] } }) </script> <h4>v-for迭代对象</h4> <div id="app3"> <ul> <li v-for="value in object"> {{ value }} </li> </ul> </div> <script> var app3 = new Vue({ el: '#app3', data: { object: { name: 'vue', url: 'http://vue.com' } } }) </script> <h4>v-for迭代对象2(提供第二个的参数为键名)</h4> <div id="app4"> <ul> <li v-for="(value, key) in object"> {{ key }} : {{ value }} </li> </ul> </div> <script> var app4 = new Vue({ el: '#app4', data: { object: { name: 'vue', url: 'http://vue.com' } } }) </script> <h4>v-for迭代对象2(提供第二个的参数为键名,第三个参数为索引)</h4> <div id="app5"> <ul> <li v-for="(value, key) in object"> {{ key }} : {{ value }} </li> </ul> </div> <script> var app5 = new Vue({ el: '#app5', data: { object: { name: 'vue', url: 'http://vue.com' } } }) </script> <h4>v-for迭代整数</h4> <div id="app6"> <ul> <li v-for="n in 10"> {{ n }} </li> </ul> </div> <script> var app6 = new Vue({ el: '#app6' }) </script> </body> </html>
结果:
补充:v-for遍历对象一般会定义一个key,一般写法如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <script src="js/vue.min.js"></script> </head> <body> <h4>v-for用法1</h4> <div id="app1"> <ol> <li v-for="(item, index) in sites" :key="index"> {{ item.name }} </li> </ol> </div> <script> var app1 = new Vue({ el: '#app1', data: { sites: [{ name: 'vue' }, { name: 'Google' } ] } }) </script> </body> </html>
结果:
3.计算属性
计算属性关键词: computed。计算属性在处理一些复杂逻辑时是很有用的。
如果我们反转一个字符串最原始的方法是:
<div id="app"> {{ message.split('').reverse().join('') }} </div> <script> var vm = new Vue({ el: '#app', data: { message: 'vue 6A!' } }) </script>
上面代码不易理解。
(1)使用计算属性进行反转: (computed调用方法是属性的调用方式 {{field}} )
例如:声明一个计算属性 reversedMessage 。提供的函数将用作属性 vm.reversedMessage 的 getter 。vm.reversedMessage 依赖于 vm.message,在 vm.message 发生改变时,vm.reversedMessage 也会更新。
<div id="app"> <p>原始字符串: {{ message }}</p> <p>计算后反转字符串: {{ reversedMessage }}</p> </div> <script> var vm = new Vue({ el: '#app', data: { message: 'vue 6A!' }, computed: { // 计算属性的 getter reversedMessage: function() { // `this` 指向 vm 实例 return this.message.split('').reverse().join(''); } } }) </script>
结果:
(2)使用methods实现(作为方法调用,需要 {{ functionName () }})
我们可以使用 methods 来替代 computed,效果上两个都是一样的,但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 methods ,在重新渲染的时候,函数总会重新调用执行。可以说使用 computed 性能会更好,但是如果你不希望缓存,你可以使用 methods 属性。
例如:cnt 是独立于 vm 对象的变量。在使用 reversedMessage 这个计算属性的时候,第一次会执行代码,得到一个值,以后再使用 reversedMessage 这个计算属性,因为 vm 对象没有发生改变,于是界面渲染就直接用这个值,不再重复执行代码。而 reversedMessage2 没有这个缓存,只要用一次,函数代码就执行一次,于是每次返回值都不一样。
<div id="app"> <p>原始字符串: {{ message }}</p> <h2>computed计算的属性</h2> <p>计算后反转字符串: {{ reversedMessage }}</p> <p>计算后反转字符串: {{ reversedMessage }}</p> <h2>methods返回的结果</h2> <p>计算后反转字符串: {{ reversedMessage2() }}</p> <p>计算后反转字符串: {{ reversedMessage2() }}</p> </div> <script> var cnt = 1; var vm = new Vue({ el: '#app', data: { message: 'vue 6A!' }, computed: { // 计算属性的 getter reversedMessage: function() { // `this` 指向 vm 实例 cnt += 1; return cnt + this.message.split('').reverse().join('') } }, methods: { reversedMessage2: function() { cnt += 1; return cnt + this.message.split('').reverse().join('') } } }) </script>
结果:
(3)computed 属性默认只有 getter ,不过在需要时你也可以提供一个 setter
<script> var vm = new Vue({ el: '#app', data: { name: '百度', url: 'http://www.baidu.com' }, computed: { site: { // getter get: function() { return this.name + ' ' + this.url + " changed" }, // setter set: function(newValue) { var names = newValue.split(' ') this.name = names[0] this.url = names[names.length - 1] } } } }) // 调用 setter, vm.name 和 vm.url 也会被对应更新 vm.site = 'vue: https://cn.vuejs.org/'; document.write('name: ' + vm.name); document.write('<br>'); document.write('url: ' + vm.url); document.write('<br>'); document.write('site: ' + vm.site); </script>
结果:
4.侦听器-watch对象和$watch实例方法
Vue.js 监听属性用 watch,我们可以通过 watch 来响应数据的变化。
例如:实现一个计数器监听
<div id="app"> <p style="font-size:25px;">计数器: {{ counter }}</p> <button @click="counter++" style="font-size:25px;">点我</button> </div> <script type="text/javascript"> var vm = new Vue({ el: '#app', data: { counter: 1 } }); // 监听counter属性的变化。nval是新值,oval是旧值 vm.$watch('counter', function(nval, oval) { alert('计数器值的变化 :' + oval + ' 变为 ' + nval + '!'); }); </script>
或者:
<div id="app"> <p style="font-size:25px;">计数器: {{ counter }}</p> <button @click="counter++" style="font-size:25px;">点我</button> </div> <script type="text/javascript"> var vm = new Vue({ el: '#app', data: { counter: 1 }, watch: { counter: function(nval, oval) { alert('计数器值的变化 :' + oval + ' 变为 ' + nval + '!'); } } }); </script>
结果:
例如:实现千米与米之间的单位转换。
以下代码中我们创建了两个输入框,data 属性中, kilometers 和 meters 初始值都为 0。watch 对象创建了两个方法 kilometers 和 meters。当我们再输入框输入数据时,watch 会实时监听数据变化并改变自身的值。
<div id="computed_props"> 千米 : <input type="text" v-model="kilometers"> 米 : <input type="text" v-model="meters"> </div> <p id="info"></p> <script type="text/javascript"> var vm = new Vue({ el: '#computed_props', data: { kilometers: 0, meters: 0 }, methods: {}, computed: {}, watch: { kilometers: function(val) { console.log(1); this.kilometers = val; this.meters = this.kilometers * 1000 }, meters: function(val) { console.log(2); this.kilometers = val / 1000; this.meters = val; } } }); // $watch 是一个实例方法 vm.$watch('kilometers', function(newValue, oldValue) { console.log(3); // 这个回调将在 vm.kilometers 改变后调用 document.getElementById("info").innerHTML = "修改前值为: " + oldValue + ",修改后值为: " + newValue; }) </script>
结果:改变千米值的时候可以看到打印的顺序是1、2、1、3