文章目录
//index.js
import Vue from "vue";
import Helloworld from "./helloworld.vue";
const vm = new Vue({
render:createElement => createElement(Helloworld)
}).$mount('#root');
v-if
,条件渲染。
条件块内的事件监听和子组件,生存还是毁灭,v-if
说了算。
如果v-if
绑定的变量值是false
,则不渲染条件块;
如果v-if
绑定的变量值是true
,则渲染条件块。
因此,如果频繁地切换v-if
对应的变量值,会有很大的渲染开销。
涉及到频繁切换,用v-show
可能比用v-if
会更合理。
v-if
模板中使用v-if
//helloworld.vue
<template>
<div v-if="isShow">hello world</div>
</template>
<script>
export default {
data(){
return {
// isShow:true
isShow:false
}
}
}
</script>
isShow
,true
时显示文本“hello world”,false
则不显示该文本。
使用render函数
//helloworld.vue
<template>
<Helloworld/>
</template>
<script>
export default {
components:{
"Helloworld":{
render:function(createElement){
if(this.isShow){
return createElement('p','hello world');
}else{
return null;
}
},
data:function(){
return {
isShow:true
}
}
}
}
}
</script>
v-if 包裹多个元素
用<template>
来包裹元素,最终的渲染结果里不包含<template>
元素。
模板里使用v-if
//helloworld.vue
<template>
<div>
<template v-if="isShow">
<p>hello</p>
<p>world</p>
</template>
</div>
<!--
<div v-if="isShow">
<p>hello</p>
<p>world</p>
</div>
-->
<!--
<template v-if="isShow">
<p>hello</p>
<p>world</p>
</template>
-->
</template>
<script>
export default {
data(){
return {
isShow:true
}
}
}
</script>
使用render函数
//helloworld.vue
<template>
<Helloworld/>
</template>
<script>
export default {
components:{
"Helloworld":{
render:function(createElement){
if(this.isShow){
return createElement(
'div',
[
createElement('p','hello'),
createElement('p','world')
]
)
}else{
return null;
}
},
data:function(){
return {
isShow:true
}
}
}
}
}
</script>
v-if/v-else
模板里使用v-if/v-else
//helloworld.vue
<template>
<div v-if="isShow">hello world</div>
<div v-else>have a nice day</div>
</template>
<script>
export default {
data(){
return {
isShow:true
}
}
}
</script>
使用render函数
//helloworld.vue
<template>
<Helloworld/>
</template>
<script>
export default {
components:{
"Helloworld":{
render:function(createElement){
if(this.isShow){
return createElement('p','hello world');
}else{
return createElement('p','have a nice day');
}
},
data:function(){
return {
isShow:true
}
}
}
}
}
</script>
v-if/v-else-if/v-else
模板里使用 v-if/v-else-if/v-else
//helloworld.vue
<template>
<div v-if="color==='red'">红</div>
<div v-else-if="color==='green'">绿</div>
<div v-else-if="color==='blue'">蓝</div>
<div v-else>黄</div>
</template>
<script>
export default {
data(){
return {
color:"red"
}
}
}
</script>
使用render函数
//helloworld.vue
<template>
<Helloworld/>
</template>
<script>
export default {
components:{
"Helloworld":{
render:function(createElement){
switch(this.color){
case "red":return createElement('div','红');break;
case "green":return createElement('div','绿');break;
case "blue":return createElement('div','蓝');break;
default:return createElement('div','黄');
}
},
data:function(){
return {
color:"red"
}
}
}
}
}
</script>
v-if 可能存在的坑
- 坑1:复用已有元素
//helloworld.vue
<template>
<div>
<template v-if="isLogged">
<label for="username">Username</label>
<input type="text" id='username' placeholder='enter your name' autocomplete="off"/>
</template>
<template v-else>
<label for="email">Email</label>
<input type="text" id='email' placeholder='enter your email' autocomplete="off"/>
</template>
<div><button @click='handleClick'>toggle</button></div>
</div>
</template>
<script>
export default {
data(){
return {
isLogged:true
}
},
methods:{
handleClick:function(){
this.isLogged = !this.isLogged
}
}
}
</script>
在username
输入框中输入文本“Tom”,切换到email
输入框时,文本“Tom”没被清除。
这是因为,从username
切换到email
, label
还是那个label
,input
还是那个input
。
vue并没有因为切换重新生成新的DOM元素,而是重用了原有的DOM元素。
针对以上问题,其解决方法就是使用key
避免元素复用。
//helloworld.vue
<template>
<div>
<template v-if="isLogged">
<label for="username">Username</label>
<input type="text" id='username' key='username' placeholder='enter your name' autocomplete="off"/>
</template>
<template v-else>
<label for="email">Email</label>
<input type="text" id='email' key='email' placeholder='enter your email' autocomplete="off"/>
</template>
<div><button @click='handleClick'>toggle</button></div>
</div>
</template>
<script>
export default {
data(){
return {
isLogged:true
}
},
methods:{
handleClick:function(){
this.isLogged = !this.isLogged
}
}
}
</script>
给input
添加key
后,从username
切换到email
, label
还是那个label
,但input
不再是原来那个input
了。
此时,input#username
和input#email
就不会互相干扰了。
- 坑2:把v-if和v-for应用在同一个元素上
<body>
<div id="root">
<ul>
<li v-for="user in users"
v-if="user.isActive"
v-bind:key="user.id"
>{{user.name}}</li>
</ul>
</div>
</body>
import Vue from "vue";
const vm = new Vue({
el:"#root",
data:{
users:[
{id:"1",name:"Nicholas",isActive:true},
{id:"2",name:"Greg",isActive:false},
{id:"3",name:"Kate",isActive:false}
]
}
});
下面的代码和以上等效。
<body>
<div id="root">
</div>
</body>
import Vue from "vue";
const vm = new Vue({
el:"#root",
data:{
users:[
{id:"1",name:"Nicholas",isActive:true},
{id:"2",name:"Greg",isActive:false},
{id:"3",name:"Kate",isActive:false}
]
},
render:function(createElement){
return createElement("ul",
this.users.map(user => {
if(user.isActive){
return createElement("li",{"key":user.id},user.name);
}
})
)
}
});
v-for
的优先级比v-if
高,所以即使只是渲染了Nicholas这一个用户,仍遍历了整个列表user。后续每次重新渲染,都将遍历完整列表。
如何破局?使用计算属性。
<body>
<div id="root">
<ul>
<li v-for="user in activeUsers"
v-bind:key="user.id"
>{{user.name}}</li>
</ul>
</div>
</body>
import Vue from "vue";
const vm = new Vue({
el:"#root",
data:{
users:[
{id:"1",name:"Nicholas",isActive:true},
{id:"2",name:"Greg",isActive:false},
{id:"3",name:"Kate",isActive:false}
]
},
computed:{
activeUsers:function(){
return this.users.filter(user => user.isActive);
}
}
});