v-show 可以根据值来决定元素是否显示(通过display来切换元素的显示状态)
v-if 可以根据表达式的值来决定是否显示元素(会直接将元素删除)
v-show通过css来切换组件的显示与否,切换时不会涉及到组件的重新渲染切换的性能比较高。
但是初始化时,需要对所有组件进行初始化(即使组件暂时不显示)
所以它的初始化的性能要差一些!
v-if通过删除添加元素的方式来切换元素的显示,切换时反复的渲染组件,切换的性能比较差。
<script setup>
import { ref } from "vue"
const isShow = ref(true)
script>
<template>
<h1>App组件h1>
<button @click="isShow = !isShow">切换button>
<template v-if="isShow">
<h2>我是一个h2h2>
<h3>我是h3h3>
template>
template>
component 是一个动态组件
<script setup>
import { ref } from "vue"
import A from "./components/A.vue"
import B from "./components/B.vue"
const isShow = ref(true)
script>
<template>
<button @click="isShow = !isShow">切换button>
<component :is="isShow ? A : B">component>
template>
浏览器在渲染页面时,做了那些事:
渲染树(Render Tree)
重排、回流
重绘
例子:
DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Documenttitle>
<style>
.box1 {
width: 200px;
height: 200px;
background-color: orange;
}
.box2 {
background-color: tomato;
}
.box3 {
width: 300px;
height: 400px;
font-size: 20px;
}
style>
head>
<body>
<button id="btn">点我一下button>
<hr />
<div id="box1" class="box1">div>
<script>
btn.onclick = () => {
// box1.classList.add("box2")
// 可以通过修改class来间接的影响样式,来减少重排的次数
//修改一次
// box1.style.width = "300px"
// box1.style.height = "400px"
// box1.style.fontSize = "20px"
// box1.classList.add("box3")
//修改两次 ,none和block修改,none之后不修改
// box1.style.display = "none"
// box1.style.width = "300px"
// box1.style.height = "400px"
// box1.style.fontSize = "20px"
// div.style.display = "block"
}
script>
body>
html>
我们可以使用 v-for
指令基于一个数组来渲染一个列表。v-for
指令的值需要使用 item in items
形式的特殊语法,其中 items
是源数据的数组,而 item
是迭代项的别名:
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
data() {
return {
items: [{ message: 'Foo' }, { message: 'Bar' }]
}
}
<li v-for="item in items">
{{ item.message }}
li>
在 v-for
块中可以完整地访问父作用域内的属性和变量。v-for
也支持使用可选的第二个参数表示当前项的位置索引。
const parentMessage = ref('Parent')
const items = ref([{ message: 'Foo' }, { message: 'Bar' }])
data() {
return {
parentMessage: 'Parent',
items: [{ message: 'Foo' }, { message: 'Bar' }]
}
}
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
li>
对于多层嵌套的 v-for
,作用域的工作方式和函数的作用域很类似。每个 v-for
作用域都可以访问到父级作用域:
<li v-for="item in items">
<span v-for="childItem in item.children">
{{ item.message }} {{ childItem }}
span>
li>
你也可以使用 of
作为分隔符来替代 in
,这更接近 JavaScript 的迭代器语法:
<div v-for="item of items">div>
你也可以使用 v-for
来遍历一个对象的所有属性。遍历的顺序会基于对该对象调用 Object.keys()
的返回值来决定。
const myObject = reactive({
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
})
<ul>
<li v-for="value in myObject">
{{ value }}
li>
ul>
可以通过提供第二个参数表示属性名 (例如 key):
<li v-for="(value, key) in myObject">
{{ key }}: {{ value }}
li>
第三个参数表示位置索引:
<li v-for="(value, key, index) in myObject">
{{ index }}. {{ key }}: {{ value }}
li>
0.title: How to do lists in Vue
1.author: Jane Doe
2.publishedAt: 2016-04-10
v-for
可以直接接受一个整数值。在这种用例中,会将该模板基于 1...n
的取值范围重复多次。
<span v-for="n in 10">{{ n }}span>
注意此处 n
的初值是从 1
开始而非 0
。
:::warning 注意
同时使用 v-if
和 v-for
是不推荐的,因为这样二者的优先级不明显。
:::
当它们同时存在于一个节点上时,v-if
比 v-for
的优先级更高。这意味着 v-if
的条件将无法访问到 v-for
作用域内定义的变量别名:
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo.name }}
li>
在外新包装一层 再在其上使用
v-for
可以解决这个问题 (这也更加明显易读):
<template v-for="todo in todos">
<li v-if="!todo.isComplete">
{{ todo.name }}
li>
template>
Vue 默认按照“就地更新”的策略来更新通过 v-for
渲染的元素列表。当数据项的顺序改变时,Vue 不会随之移动 DOM 元素的顺序,而是就地更新每个元素,确保它们在原本指定的索引位置上渲染。
默认模式是高效的,但只适用于列表渲染输出的结果不依赖子组件状态或者临时 DOM 状态 (例如表单输入值) 的情况。
为了给 Vue 一个提示,以便它可以跟踪每个节点的标识,从而重用和重新排序现有的元素,你需要为每个元素对应的块提供一个唯一的 key
attribute:
<div v-for="item in items" :key="item.id">
div>
当你使用 时,
key
应该被放置在这个 容器上:
<template v-for="todo in todos" :key="todo.name">
<li>{{ todo.name }}li>
template>
:::tip 注意
key
在这里是一个通过 v-bind
绑定的特殊 attribute。请不要和[在 v-for
中使用对象里所提到的对象属性名相混淆。
:::
推荐在任何可行的时候为 v-for
提供一个 key
attribute,除非所迭代的 DOM 内容非常简单 (例如:不包含组件或有状态的 DOM 元素),或者你想有意采用默认行为来提高性能。
key
绑定的值期望是一个基础类型的值,例如字符串或 number 类型。不要用对象作为 v-for
的 key。
<script setup>
import { ref } from "vue"
const arr = ref(["孙悟空", "猪八戒", "沙和尚", "唐僧"])
const arr2 = ref([
{
id: 1,
name: "孙悟空",
age: 18
},
{
id: 2,
name: "猪八戒",
age: 28
},
{
id: 3,
name: "沙和尚",
age: 38
}
])
script>
<template>
<button @click="arr.push('白骨精')">点我一下button>
<button @click="arr2.unshift({ id: 4, name: '唐僧', age: 16 })">
点我一下2
button>
<ul>
<li v-for="name of arr">{{ name }}li>
ul>
<ul>
<li v-for="(name, index) in arr">{{ index }} - {{ name }}li>
ul>
<div v-for="obj in arr2">{{ obj.name }} -- {{ obj.age }}div>
<hr />
<ul>
<li v-for="({ id, name, age }, index) in arr2" :key="id">
{{ name }} -- {{ age }}
<input type="text" />
li>
ul>
template>
我们可以直接在组件上使用 v-for
,和在一般的元素上使用没有区别 (别忘记提供一个 key
):
<MyComponent v-for="item in items" :key="item.id" />
但是,这不会自动将任何数据传递给组件,因为组件有自己独立的作用域。为了将迭代后的数据传递到组件中,我们还需要传递 props:
<MyComponent
v-for="(item, index) in items"
:item="item"
:index="index"
:key="item.id"
/>
不自动将 item
注入组件的原因是,这会使组件与 v-for
的工作方式紧密耦合。明确其数据的来源可以使组件在其他情况下重用。