条件渲染和循环渲染

131 阅读5分钟

条件渲染

条件渲染主要为v-if和v-show

v-if="表达式"
v-show="表达式"
可以是任意的表达式,会将表达式做布尔判断,v-if和v-show功能上表达式为true就显示,false就隐藏,但两者底层实现的做法不同。
    <div id="app">
        <div v-if="flag">1</div>
        <div v-show="msg==2">2</div>
        <div>
            <button @click="fn">点击我删除1和2</button>
        </div>
    </div>
    <script>
        new Vue({
            el:"#app",
            data:{
                flag:true,
                msg:2
            },
            methods: {
                fn(){
                    this.flag=!this.flag;
                    this.msg=1;
                }
            }
        });
    </script>

image.png

1.v-if的做法是删除元素节点,v-show做法是操作css的隐藏元素,display:none

两个的使用场景(面试)

这个两个谁好?(面试)

根据它们底层的设计不一样有各自的使用场景,v-if具有较高的渲染消耗,常常用在用户不常切换的模块中,就避免了过多的内存消耗,v-show具有较高的内存消耗,常常用在用户频繁切换的模块中,元素节点不删除还是在会占用内存就避免了渲染消耗。

v-else和v-else-if

写法:

  (1).v-if=“表达式”
  (2).v-else-if=“表达式”
  (3).v-else=“表达式”

psv-else-if、v-else必须和v-if一起使用,要求结构不能被“打断”,v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别

    <div id="demo">
		<h2>当前的n值是:{{n}}</h2>
		<button @click="n++">点我n+1</button>
		<!-- v-else和v-else-if -->
		<div v-if="n === 1">1</div>
		<div v-else-if="n === 2">2</div>
		<div v-else-if="n === 3">3</div>
		<div v-else>不是1、2、3</div>
	</div>
	<script type="text/javascript">
		const vm = new Vue({
			el: '#demo',
			data: {
				n: 0
			}
		})
	</script>

循环渲染

v-for 指令可以基于一个数组或对象来渲染页面。v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是要被遍历的数据源,而 item 则是被遍历的数据源中的元素。

用于遍历数组和对象

v-for指令的元素会连同元素本身以及元素的子元素一起都会克隆显示在页面上

image.png

image.png

1.v-for遍历数组时,第一个参数是当前项,第二个参数是当前项的索引。
2.v-for遍历对象时,只传入一个参数就是遍历的对象的键值,也可以传入两个参数,第一个参数是键值,第二个参数是键名,第三个参数是索引
在遍历对象时,会按 Object.keys() 的结果遍历
    <div id="app">
        <div v-for="el in obj">
            <h2>{{el}}</h2>
        </div>
        <div v-for="(value,key) in obj" :style="{color:color}">
            <p>{{key}}:{{value}}</p>
        </div>
    </div>
    <script>
        new Vue({
            el: "#app",
            data: {
                color:"gold",
                arr: [{ title: "启示录", music: ["Gloria", "HELL"] }, { title: "Make up", music: ["Nice body", "Fake it", "谈"] }],
                obj: {
                    name: "With Love J",
                    featured: "Fly",
                    more:"Golden Sky"
                }
            }
        });
    </script>

image.png

处于同一个节点中v-for与v-if的优先级(面试)

vue2.0中v-if与v-for,写到一个元素时v-for的优先级更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中。就会引起两个问题,一个是有两层for循环嵌套时,当if的数据做判断时需要用第一层的for中的数据,但实际情况却是用的第二层for循环中的数据,就会导致业务出错;另外一个问题是遍历数据源每新增一组数据就会对遍历数据源的每一项再做一遍v-if 循环,然后for循环渲染,如此就增大了渲染效率。

解决方法:

1.写成嵌套关系,将v-if嵌套在v-for的外层,但是如此会产生新的问题:外层if的div标签没有实质作用但也会创建一个挂载到DOMTree中,所以采用第2种方案

2.把外层的v-if写在template中,是由Vue框架提供,其实质是dom操作中创建的DocumentFragment元素,该节点不会直接添加到文档树中就不会占用额外的资源。

第一个问题产生造成业务错误

    <div id="box">
        <div v-for="el in album">
            <h1 v-text="el.name"></h1>
            <div v-for="el in el.music" v-if="el.onlinyear>5">
                <p style="color: gold;">{{el}}</p>
            </div>
        </div>
    </div>
    <script>
        new Vue({
            el: "#box",
            data: {
                album: [
                    {
                        name: "With Love J",
                        music: ["Fly", "Golden Sky", "Big Mini World", "Falling Crazy Love", "Love Me The Same"],
                        onlineyear:6
                    },
                    {
                        name: "City Zoo",
                        music: ["句号", "摩天动物园", "依然睡公主", "差不多姑娘", "Fly Away","透明","灰狼","别勉强","Walk on Water","很久以后","萤火","多美丽","好想好想你"],
                        onlineyear:3
                    },
                    {
                        name: "Make up",
                        music: ["Nice body", "Fake it", "谈"],
                        onlineyear:8
                    }
                ]
            }
        });
    </script>

image.png

因为v-if="el.onlinyear"的el是第二层for循环的el也就是取出的music数组,取不到onlinyear这个属性是undefined,v-if的表达式永远不会成立文档树中就不会有符合条件的元素节点

第1种解决方法

    <div id="box">
        <div v-for="el in album">
            <h1 v-text="el.name"></h1>
            <div v-if="el.onlineyear>5">
                <p style="color: gold;" v-for="el in el.music">{{el}}</p>
            </div>
        </div>
    </div>
    <script>
        new Vue({
            el: "#box",
            data: {
                album: [
                    {
                        name: "With Love J",
                        music: ["Fly", "Golden Sky", "Big Mini World", "Falling Crazy Love", "Love Me The Same"],
                        onlineyear: 6
                    },
                    {
                        name: "City Zoo",
                        music: ["句号", "摩天动物园", "依然睡公主", "差不多姑娘", "Fly Away", "透明", "灰狼", "别勉强", "Walk on Water", "很久以后", "萤火", "多美丽", "好想好想你"],
                        onlineyear: 3
                    },
                    {
                        name: "Make up",
                        music: ["Nice body", "Fake it", "谈"],
                        onlineyear: 8
                    }
                ]
            }
        });
    </script>

image.png

第2种解决方案:

    <div id="box">
        <div v-for="el in album">
            <h1 v-text="el.name"></h1>
            <template v-if="el.onlineyear>5">
                <p style="color: gold;" v-for="el in el.music">{{el}}</p>
            </template>
        </div>
    </div>
    <script>
        new Vue({
            el: "#box",
            data: {
                album: [
                    {
                        name: "With Love J",
                        music: ["Fly", "Golden Sky", "Big Mini World", "Falling Crazy Love", "Love Me The Same"],
                        onlineyear: 6
                    },
                    {
                        name: "City Zoo",
                        music: ["句号", "摩天动物园", "依然睡公主", "差不多姑娘", "Fly Away", "透明", "灰狼", "别勉强", "Walk on Water", "很久以后", "萤火", "多美丽", "好想好想你"],
                        onlineyear: 3
                    },
                    {
                        name: "Make up",
                        music: ["Nice body", "Fake it", "谈"],
                        onlineyear: 8
                    }
                ]
            }
        });
    </script>

image.png

v-for绑定key的意义(面试)

1.key是虚拟DOM对象的标识,当数据发生变化时Vue会根据新数据生成新虚拟DOM,然后进行新虚拟DOM与旧虚拟DOM做比较。

2.比较规则:旧虚拟DOM中找到了与新虚拟DOM相同的key,当虚拟DOM中内容没变,直接使用之前的真实DOM,变了则生成新的真实DOM替换页面中之前的真实DOM。旧虚拟DOM中未找到与新虚拟DOM相同的key,就创建新的真实DOM然后渲染在页面中。

3.用index作为key可能会引发的问题:若对数据进行逆序添加和逆序删除等破坏顺序操作会产生没有必要的真实DOM更新,界面渲染没问题但效率低。如果结构中包含输入类的DOM会产生错误的DOM更新导致界面渲染有问题

4.最好使用每条数据的唯一标识作为key。

简答:因为Vue在刷新页面组件时,会把旧节点跟新的创建的实例的节点做比较,如果要增加节点,并不会删除旧节点,而是复用。这样会导致节点跟数据没有绑定关系而重新渲染,用唯一的key值可以将数据与节点绑定起来以及key的作用主要是为了高效的更新虚拟DOM。

<div id="app">
        <h1>请选择你最喜欢的5件商品</h1>
        <div v-for="el in arr" :key="el.id">
            <input type="checkbox" name="goods" :value="el.id">
            <b>{{el.title}}</b>
        </div>
        <button @click="addmore">加载更多</button>
    </div>
    <script>
        new Vue({
            el: "#app",
            data: {
                id: 5,
                arr: [{ id: 1, title: "包包1", price: 123 },
                { id: 2, title: "鞋子1", price: 123 },
                { id: 3, title: "衣服1", price: 123 },
                { id: 4, title: "商品1", price: 123 }]
            },
            methods: {
                addmore() {
                    let obj = { id: this.id++, title: "商品" + this.id, price: 123 };
                    this.arr.unshift(obj);
                }
            }
        });

    </script>
    //el.id就是数据容器中的每一个数据都有的唯一的值