若有疑问,欢迎评论,我会尽快回复。
致读者(选读)
有些朋友是在搜索“v-show实现tab页切换”等需求时,访问到本文的。
通过改变CSS/DOM切换的思路可行,但繁琐且存在缺陷,可能会遇到页面走样,与生命周期不协调,传值麻烦等问题。
在现代前端开发中,针对tab切换类需求,更建议使用前端路由vue-router或动态组件 v-bind:is来实现。
vue中的显示切换更适用于实现静态内容切换,而不适用于复杂业务组件的切换。
显示切换
在Vue中,实现显示切换,有以下几种手段:
- 使用v-if指令
- 使用v-show指令
- 动态绑定display
- 动态绑定visibility
- 动态绑定opacity
下面将通过案例对比它们的异同。
1.动绑display
动态绑定display,通过添加或删除“display:none”属性实现显示切换。
示例:
我们对.middle
节点动态绑定display属性;
同时为.bedroom
节点设置样式display: block
,测试重写后代节点display属性的效果
<template>
<div class="hello">
<div class="top">3楼</div>
<div class="middle" :style="display">
<div class="bedroom room">2楼卧室</div>
<div class="bathroom room">2楼洗手间</div>
</div>
<div class="bottom">Floor 3</div>
<input type="button" @click="toggle()" value="切换">
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
display: ""
};
},
methods: {
toggle() {
if (this.display === "display:none") {
this.display = "";
} else {
this.display = "display:none";
}
}
}
};
</script>
<style scoped>
/* ... */
.bedroom {
/* ... */
display: block;
}
/* ... */
</style>
效果如下:
实验结论
-
当节点的属性为display:none时,其自身与后代节点不再生成盒模型以占位,但html节点并没有真的被删除。
-
当祖先节点为display:none时,后代节点均受影响,且重写子节点display属性无效。
W3C CSS2.1文档原文
This value causes an element to generate no boxes in the formatting structure (i.e., the element has no effect on layout). Descendant elements do not generate any boxes either; this behavior cannot be overridden by setting the ‘display’ property on the descendants.
Please note that a display of ‘none’ does not create an invisible box; it creates no box at all. CSS includes mechanisms that enable an element to generate boxes in the formatting structure that affect formatting but are not visible themselves. Please consult the section on visibility for details.
2.v-show
使用v-show指令,实际就是根据绑定的布尔数据,对元素进行动态添加或取消“display:none”进行显示切换的。
3.v-if
与v-show不同的是,v-if是根据条件渲染元素,一旦不满足条件,元素则会直接被删除。
4.动绑visibility
动态绑定visibility,通过修改“visibility”属性实现显示切换。
visibility:hidden可让元素生成不可见盒,元素虽不可见,但仍生成盒模型,保持占位。
示例:
为验证visibility是否影响元素绑定的事件,为.middle
节点添加点击事件(点击效果:在3楼显示 hello!)。
为验证visibility对后代元素影响,为.bedroom
设置visibility:visible的属性
<template>
<div class="hello">
<div class="top">3楼</div>
<div class="middle" :style="visibility" @click="greet()">
<div class="bedroom room">2楼卧室</div>
<div class="bathroom room">2楼洗手间</div>
</div>
<div class="bottom">Floor 3 {{this.greeting}}</div>
<input type="button" @click="toggle()" value="切换">
</div>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
visibility: "visibility:visible",
greeting:" "
};
},
methods: {
toggle() {
if (this.visibility === "visibility:visible") {
this.visibility = "visibility:hidden";
} else {
this.visibility = "visibility:visible";
}
},
greet(){
this.greeting = "Hello!"
}
}
};
</script>
<style scoped>
/* ... */
.bedroom {
/* ... */
visibility: visible;
}
/* ... */
</style>
效果如下:
点击效果描述:
- 点击不可见部分不触发点击事件, 点击可见的子节点触发点击事件。
实验结论:
- visibility属性不影响元素占位。元素不可见时仍占位,布局不塌陷。
- 子元素默认继承父元素visibility属性,但子元素若重写属性,则不受父级影响。
- hidden元素不能触发主动事件,但如果它的子元素可见,则可以触发事件。
5.动绑opacity
动绑opacity属性,通过修改元素的透明度进行显示切换。
示例:
- 为测试祖先opacity属性对后代的影响,为
.bedroom
设定固定的opacity:1 - 为测试opacity属性对事件触发的影响,为
middle
添加点击事件
<template>
<div class="hello">
<div class="top">3楼</div>
<div class="middle" @click="greet()" :style="opacity">
<div class="bedroom room">2楼卧室</div>
<div class="bathroom room">2楼洗手间</div>
</div>
<div class="bottom">Floor 3 {{this.greeting}}</div>
<input type="button" @click="toggle()" value="切换">
</div>
</template>
<script>
export default {
data() {
return {
opacity: "opacity:1",
greeting: " "
};
},
methods: {
greet() {
this.greeting = "Hello!";
},
toggle() {
if (this.opacity === "opacity:1") {
this.opacity = "opacity:0";
} else {
this.opacity = "opacity:1";
}
}
}
};
</script>
<style scoped>
/* ... */
.middle {
/* ... */
opacity: 1;
}
.bedroom {
/* ... */
opacity: 1;
}
</style>
效果如下:
实验结论:
- opacity属性仅改变元素的透明度,不影响元素的占位。
- opacity属性不可继承,但祖先元素的opacity会影响后代。后代元素的opacity取最小值显示。若祖先元素opacity为0,后代为1,则0生效。若祖先为1,后代为0.5,则0.5生效。
- opacity属性不影响事件触发
提问集合
watch监听
需求描述:根据input中的值同时控制两个按钮?即当input的值存在时,A按钮显示,B按钮隐藏。当input的值为空时,A按钮隐藏,B按钮显示
解决方法: 使用vue的watch监听进行解决。
<body>
<div id="app">
<input type="text" v-model="flagVal">
<button v-show="!showFlag">1</button>
<button v-show="showFlag">2</button>
</div>
<script>
let vm = new Vue({
el:'#app',
data() {
return {
flagVal: null,
showFlag: true
}
},
watch: {
flagVal(val) {
console.log(val)
if(val){
this.showFlag = false
}else{
this.showFlag = true
}
}
}
})
</script>
</body>