代码javascript
有时数据中携带了Html标签,输出它们时,按文本解析,如:css
new Vue({ data: { title:'<h3>使用<code>v-html</code>输出原生的html</h3>', } }).$mount('#app-1')
<div id="app-1" > <div>{{title}}</div> </div>
使用原生指令v-html
解析数据中标签为原生htmlhtml
<div id="app-1" > <div v-html="title"></div> </div>
你的站点上动态渲染的任意 HTML 可能会很是危险,由于它很容易致使 XSS 攻击。请只对可信内容使用 HTML 插值,毫不要对用户提供的内容使用插值。
如:vue
new Vue({ data: { title:'<h3>使用<code>v-html</code>输出原生的html</h3>', recieveMessage:'', } }).$mount('#app-1')
<div id="app-1" > <div v-html="title"></div> <input type="text" style="width:300px" v-model="recieveMessage"/> <div> <output v-html="recieveMessage"></output> </div> </div>
使用时要注意这种状况。插入<script>
几乎能够作任何事情,还有插入无数<img>
占用带宽。java
当v-if
条件为truthy时,动态插入内容。
好比在晚7点到早上7点咱们插入如下内容:git
new Vue({ computed: { isNight() { return new Date().getHours() < 7 || new Date().getHours() > 19 } } }).$mount('#app-2')
<div id="app-2"> <div v-if="isNight" style="font-size:30px;color:yellow;background: black;width:300px"> ? it's night </div> </div>
也可使用v-show="isNight"
显示和隐藏内容web
<div id="app-2"> <div v-show="isNight" style="font-size:30px;color:yellow;background: black;width:300px"> ? it's night </div> </div>
二者区别为:v-show
元素始终存在,经过display控制显示/隐藏。而v-if
的转换要经历组件的销毁和重建。使用v-show
初始会有开销,而v-if
初始条件若为falsy,那么什么也不会作,节省用户的 CPU 时间。可是若是v-if
频繁切换条件,那么开销又比v-show
大的多。数组
能够用v-else
和v-else-if
做分支,注意前后顺序,顺序错误则无效。app
<div v-else style="font-size:30px;color:orange;background: lightblue;width:300px"> ? it's day </div>
上面都在外包元素<div>
上使用条件指令,若是不想使用可见元素包裹内容,可使用<template>
标签测试
<template v-if="isNight"> <span>?</span> <span>it's night</span> </template>
相似其余语言{}
的做用
if(isNight){ //... }
以上,若v-if
新插入部分与被移除部分有元素是类似的,那么为了效率这些元素会被复用,不会从新渲染。
new Vue({ el:'#app-3', data: { loginType: 'username' }, methods: { troggle(){ this.loginType = this.loginType==='username'?'email':'username' } } })
<div id="app-3"> <dl> <dt>key</dt> <dd v-if="loginType === 'username'"> <label>Username</label> <input placeholder="Enter your username"> </dd> <dd v-else> <label>Email</label> <input placeholder="Enter your email address"> </dd> <dd> <button @click="troggle">switch</button> </dd> </dl> </div>
input
和label
俩元素自己没有被替换,所以input
中输入的内容在切换时会保留,而input
的 placeholder 和label
的内容被替换。
若是使用key
特性对元素做惟一标识,那么该元素必备替换。
<div id="app-3"> <dl> <dt>不使用key</dt> <dd v-if="loginType === 'username'"> <label>Username</label> <input placeholder="Enter your username" key="username"> </dd> <dd v-else> <label>Email</label> <input placeholder="Enter your email address" key="email"> </dd> <dd> <button @click="troggle">switch</button> </dd> </dl> </div>
设置key
后,切换内容时input
的值不在保留。key
主要在v-for
里使用,以区分列表项,还有动画部分会大量使用,由于元素复用致使淡入淡出动画失效。
列表使用细节比较杂碎,按官网教程一个个试下就好了。
通常状况下用法v-for="列表项 in|of 列表|整数"
如
<h3>以一个整数进行遍历</h3> <span v-for='n in 10'> {{n}} </span> <h3>票房</h3> <ul> <li v-for="bo of boxOffice"> {{bo.name}} {{bo.year}} ({{bo.sells}}$ ) </li> </ul>
new Vue({ el: '#app-4', data: { query: '', boxOffice: [ { name: 'Avatar', year: 2009, sells: '27.88' }, { name: 'Frozen', year: 2013, sells: '12.765' }, { name: 'Furious 7', year: 2015, sells: '15.15' }, { name: 'Iron Man 3', year: 2013, sells: '12.154' }, { name: 'Titanic', year: 1997, sells: '21.868' }, { name: 'Spectre', year: 2015, sells: '8.722' }, { name: 'Inception', year: 2010, sells: '8.255' }, { name: 'Jurassic World', year: 2015, sells: '16.99' } ] } })
以上的boxOffice
能够是个数组,固然咱们也能够遍历一个对象的值。如给电影 Avatar 加一个导演属性
{ name: 'Avatar', year: 2009, sells: '27.88', director:{firstname:'yannie',lastname:'cheung',age:'17'} },
在列表中嵌套一个列表显示导演信息
<li v-for="bo of boxOffice"> {{bo.name}} {{bo.year}} ({{bo.sells}}$ ) <ul> <li v-for="value of bo.director">{{value}}</li> </ul> </li>
在列表遍历中还能够引用列表索引,对象的遍历中引用键值与索引,索引从0开始。
列表: (列表项,索引) in 列表
对象: (值,键值,索引) in 对象
修改示例以显示这些内容
<ul> <li v-for="(bo,index) of boxOffice"> {{index+1}}、{{bo.name}} {{bo.year}} ({{bo.sells}}$ ) <ul> <li v-for="(value,key,index) of bo.director">{{index+1}}、{{key}}:{{value}}</li> </ul> </li> </ul>
在遍历对象时,是按 Object.keys() 的结果遍历,可是不能保证它的结果在不一样的 JavaScript 引擎下是一致的。
与v-if
相似的,当列表被更新时,这些已被渲染的列表元素不会从新渲染,只会改变其中的内容。咱们修改以上示例,点击按钮列表会按票房从新排序,咱们再为每个li
加上动画。
data(){ //... isSort:false }, //...... //点击按钮,在原顺序与票房顺序切换 computed: { //点击按钮,在原顺序与票房顺序切换 sortBySells(){ var newArr = this.boxOffice.concat() if(this.isSort){ return newArr.sort((b1,b2) => b1.sells - b2.sells) }else{ return this.boxOffice } }, //... }
<h3>票房</h3> <ul> <!-- 测试基本功能 --> <!-- <li v-for="(bo,index) of boxOffice"> --> <!-- 测试特性key --> <li v-for="(bo,index) in sortBySells" class="animate"> {{index+1}}、{{bo.name}} {{bo.year}} ({{bo.sells}}$ ) <ul> <li v-for="(value,key,index) of bo.director">{{index+1}}、{{key}}:{{value}}</li> </ul> </li> </ul>
.animate { display: block; margin-bottom: 10px; color: #fff; background: #2e8b57; border-radius: 3px; -webkit-animation: animate 5s infinite; animation: animate 5s infinite; } @keyframes animate { 0% { width: 350px; } to { width: 600px; } }
当列表从新排列时,动画没有中断从新开始,说明这些<li>
元素没有被从新渲染,它们被复用了。
如今为列表加上key
<li v-for="(bo,index) in sortBySells" :key="bo.sells" class="animate">
设置key
后,某些元素的动画中断并从新开始,说明元素的确被从新渲染了。咱们设置报价为key
的值,若是设置index
为值,列表仍是会被彻底的复用。
在以上key
的使用中已经看到咱们对列表进行的排序是在计算属性中进行的,这种方法的形式通常为这样:v-for="项 in 计算属性"
虽然处理列表首选计算属性,但也可使用方法,特别是在计算属性不适用的状况下。v-for="项 in 方法(参数)"
改写以上示例,使用方法对列表进行排序,只为演示,最优仍是使用计算属性
methods: { //点击按钮,在原顺序与票房顺序切换 sort(isSort) { var newArr = this.boxOffice.concat() return isSort ? newArr.sort((b1, b2) => b1.sells - b2.sells) : this.boxOffice } }
<li v-for="(bo,index) in sort(isSort)" :key="bo.sells" class="animate">
效果与使用计算属性同样。
变异方法和非变异方法:以上对列表使用了sort()
方法,这个方法会改变原始数组,因此咱们用concat()
复制出一份,不改变原数据。这里sort()
为变异方法,concat()
为非变异方法。
filter()
是一个非变异方法,好比咱们过滤出2010年前的票房大于10亿的电影
computed: { //... //2010以前票房大于10亿的电影,调用两个方法 filterBoxOffice() { return this.highSells(this.beforeYear(this.boxOffice)) }, //... }, methods: { //... beforeYear(list) { return list.filter(bo => bo.year <= 2010) }, highSells(list) { return list.filter(bo => bo.sells <= 10.0) }, }
<ul> <li v-for="bo in beforeYear(highSells(boxOffice))"> <!-- <li v-for="bo in filterBoxOffice"> --> {{bo.name}} {{bo.year}} ({{bo.sells}}$ ) </li> </ul>
如上,可使用一个计算属性返回过滤结果,也能够直接连续调用两个方法。
又好比,咱们根据文本输入来进行过滤。
<h3>过滤</h3> <input type="text" v-model="query" /> <ul> <li v-for="bo in queryBo"> {{bo.name}} {{bo.year}} ({{bo.sells}}$ ) </li> </ul>
因为在filter()
里不能使用this
引用 vue 实例,所以在外部先把它赋给变量 vm
queryBo() { var vm = this var noblank = this.boxOffice.filter(item => Number(vm.query) === item.year) return this.query ? noblank : this.boxOffice }
如下两种情形的数据变化,vue没法再视图中做出响应
当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
当你修改数组的长度时,例如:vm.items.length = newLength
如添加如下代码,点击按钮修改
modifyItem(){ this.boxOffice[0] = { name: 'The Last Jedi', year: 201  7, sells: '13.32', director: { firstname: 'yannie', lastname: 'cheung', age: '17' } } this.boxOffice.length = 5 }
<button @click="modifyItem" style="margin-left:20px">vue.set test</button>
没有任何响应,但事实上值已经更新,
不过设置某索引对应对象的属性,时会有响应的
modifyItem(){ //无响应 this.boxOffice[0] = { name: 'The Last Jedi', year: 2017, sells: '13.32', director: { firstname: 'yannie', lastname: 'cheung', age: '17' } } this.boxOffice.length = 5 //有响应 this.boxOffice[1].name = 'somename' }
索引值和长度的改变是由于其余改变(this.boxOffice[1].name = 'somename')触发了响应,而并不是他们自身是响应式的。
为了解决这个问题提供了两种:使用变异方法splice()
和Vue.set
//设置 modifyItem(){ //无响应 // this.boxOffice[0] = { name: 'The Last Jedi', year: 2017, sells: '13.32', director: { firstname: 'yannie', lastname: 'cheung', age: '17' } } // this.boxOffice.length = 5 //无响应的解决方法 // this.$set 等价于 Vue.set Vue.set(this.boxOffice, 0, { name: 'The Last Jedi', year: 2017, sells: '13.32', director: { firstname: 'yannie', lastname: 'cheung', age: '17' }}) // this.boxOffice.splice(0, 1, { name: 'The Last Jedi', year: 2017, sells: '13.32', director: { firstname: 'yannie', lastname: 'cheung', age: '17' }}) //修改长度 this.boxOffice.splice(5) //有响应 // this.boxOffice[1].name = 'somename' }
此时,点击按钮设置新状态,马上做出响应。
对于对象而言,属性的添加或删除没法响应,如
//添加对象属性 modifyObject(){ this.boxOffice[0].director.sex = 'male' }
可使用Vue.set
解决这个问题
或者将对象原先属性和新增属性合并成新对象再赋给该对象,这使咱们能够添加多个属性,如:
//methods //添加对象属性 modifyObject(){ // 无响应 // this.boxOffice[0].director.sex = 'male' //解决方法 Vue.set(this.boxOffice[0].director, 'sex', 'male') this.boxOffice[0].director = Object.assign({}, this.boxOffice[0].director,{ aliasname:'kanzaki urumi', graduation: 'NUIST' }) }
同 v-if,包裹多个元素,下节有使用到。
v-for 的优先级比 v-if 高。就是说能够向下面这样,先展开全部列表项,以后 v-if 将做用于每一个列表项。
为影片添加是否上映属性run
boxOffice: [ { name: 'Avatar', year: 2009, sells: '27.88',run:true, director: { firstname: 'yannie', lastname: 'cheung', age: '17' } }, { name: 'Frozen', year: 2013, sells: '12.765',run:false }, { name: 'Furious 7', year: 2015, sells: '15.15',run:true }, { name: 'Iron Man 3', year: 2013, sells: '12.154',run:false }, { name: 'Titanic', year: 1997, sells: '21.868',run:false }, { name: 'Spectre', year: 2015, sells: '8.722',run:true }, { name: 'Inception', year: 2010, sells: '8.255',run:false }, { name: 'Jurassic World', year: 2015, sells: '16.99',run:false } ]
<h3>v-for|if 的优先级</h3> <ul> <li v-for="bo in boxOffice" v-if="bo.run"> {{bo.name}} {{bo.year}} ({{bo.sells}}$ ) </li> </ul> v>
若是想设置在某条件下循环是否执行,那么能够在外层加上 v-if
<h3>v-for|if 的优先级</h3> <ul> <template v-if="boxOffice.length"> <li v-for="bo in boxOffice" v-if="bo.run"> {{bo.name}} {{bo.year}} ({{bo.sells}}$ ) </li> </template> <li v-else>没有影片</li> </ul>
和在原生元素上使用同样,只是必须使用 key
new Vue({ data: { boxOffice: [ { id:1,name: 'Avatar', year: 2009, sells: '27.88', run: true, director: { firstname: 'yannie', lastname: 'cheung', age: '17' } }, { id:2,name: 'Frozen', year: 2013, sells: '12.765', run: false }, { id:3,name: 'Furious 7', year: 2015, sells: '15.15', run: true }, { id:4,name: 'Iron Man 3', year: 2013, sells: '12.154', run: false }, { id:5,name: 'Titanic', year: 1997, sells: '21.868', run: false }, { id:6,name: 'Spectre', year: 2015, sells: '8.722', run: true }, { id:7,name: 'Inception', year: 2010, sells: '8.255', run: false }, { id:8,name: 'Jurassic World', year: 2015, sells: '16.99', run: false } ] }, components: { 'child': { props:['bo'], template: '<li>{{bo.id}}、{{bo.name}}</li>' } } }).$mount('#app-5')
<div id="app-5"> <child v-for="bo in boxOffice" :bo="bo" :key="bo.id"></child> </div>
更多内容参见组件与单文件组件部分