Vue3 中的模板语法
目录
- 前言
- 一、什么是模板语法?
- 二、内容渲染指令
- 1. v-text
- 2. {{ }} 插值表达式
- 3. v-html
- 三、双向绑定指令
- 1. v-model
- 2. v-model的修饰符
- 四、属性绑定指令
- 1. 动态绑定多个属性值
- 2. 绑定class和style属性
- 五、条件渲染指令
- 1. v-if、v-else-if、v-else
- 2. v-show
- 3. v-if和v-show的区别
- 六、事件绑定指令
- 1. 事件修饰符
- 2. 按键修饰符
- 3. 鼠标按键修饰符
- 七、列表渲染指令
- 1. v-for渲染数组
- 2. v-for渲染对象
- 3. 通过 key 管理状态
- 总结:
前言
Vue.js
从版本1.x
到版本3.x
,官方代码案例和推荐使用都是模板语法,那么本篇文章我们也根据官方的推荐,来了解一下模板语法是怎么一回事。
一、什么是模板语法?
我们可以把 Vue.js
的模板语法,直接理解为 HTML
语法的一种扩展,它所有的模板节点声明、属性设置和事件注册等都是按照 HTML
的语法来进行扩展设计的。按照官方的说法就是“所有的 Vue
模板都是语法层面合法的 HTML
,可以被符合规范的浏览器和 HTML
解析器解析”。
Vue 使用一种基于 HTML 的模板语法,使我们能够声明式地将其组件实例的数据绑定到呈现的 DOM 上
二、内容渲染指令
1. v-text
使用 v-tex
t指令,将数据采用纯文本方式填充其空元素中
// 组合式
<script setup>import { reactive } from 'vue'let student = reactive({name: 'Jack',desc: '<h3>我是来自中国的小朋友!</h3>'})</script><template><!-- 使用v-text指令,将数据采用纯文本方式填充其空元素中 --><div v-text="student.name"></div><!-- v-text:以纯文本的方式显示数据 --><div v-text="student.desc"></div><!-- 下面的代码会报错:div 元素不是空元素 --><!-- <div v-text="student.name">这是原始的div数据</div> --></template>
2. {{ }} 插值表达式
在元素中的某一位置采用纯文本的方式渲染数据
// 组合式
<script setup>import { reactive } from 'vue'let student = reactive({name: 'Jack',desc: '<h3>我是来自中国的小朋友!</h3>'
})</script><template><!-- 插值表达式:在元素中的某一位置采用纯文本的方式渲染数据 --><div>这是一个 DIV 元素,{{ student.name }},{{ student.desc }}</div></template>
3. v-html
使用 v-html
指令,将数据采用 HTML
语法填充其空元素中
// 组合式
<script setup>import { reactive } from 'vue'let student = reactive({name: 'Jack',desc: '<h3>我是来自中国的小朋友!</h3>'
})</script><template><!-- 使用v-html指令,将数据采用HTML语法填充其空元素中 --><div v-html="student.name"></div><!-- v-html:以 HTML 语法显示数据 --><div v-html="student.desc"></div><!-- 下面的代码会报错:div 元素不是空元素 --><!-- <div v-html="student.name">这是原始的div数据</div> --></template>
三、双向绑定指令
1. v-model
v-model
双向数据绑定指令,视图数据和数据源同步
一般情况下 v-model
指令用在表单元素中:
- 文本类型的
<input>
和<textarea>
元素会绑定value
属性并侦听input
事件 <input type="checkbox">
和<input type="radio">
会绑定checked
属性并侦听change
事件<select>
会绑定value
属性并侦听change
事件
// 组合式
<script setup>import { ref } from 'vue' let inputText = ref('ABC') // 单行文本框
let message = ref('本次更新有以下几点:……') // 多行文本框
let open = ref(true) // 开灯(复选框)
let determine = ref('不确定') // 是否确定(复选框)
let likes = ref(['YMQ']) // 兴趣爱好(复选框)
let sex = ref('woman') // 性别(单选按钮)
let level = ref('B') // // 证书等级(单选下拉框)
let city = ref(['苏C', '苏B']) // 去过的城市(多选下拉框)</script><template><!-- 单行文本框 --><input type="text" v-model="inputText"><hr><!-- 多行文本框 --><textarea v-model="message"></textarea><hr><!-- 默认情况下,复选框的值:true/false --><input type="checkbox" v-model="open"> 灯<hr><!-- 自定义复选框值: true-value/false-value --><input type="checkbox" true-value="确定" false-value="不确定" v-model="determine"> 是否确定<hr><input type="checkbox" value="LQ" v-model="likes"> 篮球<input type="checkbox" value="ZQ" v-model="likes"> 足球<input type="checkbox" value="YMQ" v-model="likes"> 羽毛球<input type="checkbox" value="PPQ" v-model="likes"> 乒乓球<hr><input type="radio" value="man" v-model="sex"> 男<input type="radio" value="woman" v-model="sex"> 女<hr>证书等级:<select v-model="level"><option value="C">初级</option><option value="B">中级</option><option value="A">高级</option></select><hr>去过的城市:<select multiple v-model="city"><option value="苏A">南京</option><option value="苏B">无锡</option><option value="苏C">徐州</option><option value="苏D">常州</option></select></template>
2. v-model的修饰符
修饰符 | 作用 | 示例 |
---|---|---|
.number | 自动将用户的输入值转为数值类型 | <input v-model.number="age" /> |
.trim | 自动过滤用户输入的首尾空白字符 | <input v-model.trim="msg" /> |
.lazy | 在 chang 时而非 input 时更新 | <input v-model.lazy="msg" /> |
// 组合式
<script setup>import { ref } from 'vue' let age = ref(20)
let nickname = ref('')</script><template><p>将用户输入的值转成数值 .number,懒更新 .lazy</p><!-- 。number 将用户输入的值转成数值,如果用户输入的内容无法转成数字,将不会更新数据源 --><!-- .lazy 在 change 跟新数据源,而不是 input --><input type="text" v-model.lazy.number="age"><hr><p>去掉首尾空白字符</p><input type="text" v-model.trim="nickname"></template>
四、属性绑定指令
- 响应式地绑定一个元素属性,应该使用
v-bind:
指令 - 如果绑定的值是
null
或者undefined
,那么该属性将会从渲染的元素上移除 - 因为
v-bind
非常常用,我们提供了特定的简写语法:
// 组合式
<script setup>import { reactive } from 'vue'let picture = reactive({src: 'https://uploadfile.bizhizu.cn/2015/0424/20150424015229741.jpg', // 图像地址width: 200 // 显示宽度
})</script><template><input type="range" min="100" max="500" v-model="picture.width"><hr><!-- v-bind: 为 src 属性绑定指定的数据源 --><img v-bind:src="picture.src" v-bind:width="picture.width"><hr><!-- : 是 v-bind: 的缩写形式 --><img :src="picture.src" :width="picture.width"><hr><!-- 如果绑定的值是 null 或者 undefined,那么该属性将会从渲染的元素上移除 --><button @click="picture.width = null">设置宽度为NULL</button></template>
1. 动态绑定多个属性值
直接使用 v-bind
来为元素绑定多个属性及其值
// 组合式
<script setup>import {reactive} from 'vue'let attrs = reactive({class: 'error',id: 'borderBlue'
})</script><template><!-- 直接使用 v-bind 来为元素绑定多个属性及其值 --><button v-bind="attrs">我是一个普通的按钮</button></template><style>.error {background-color: rgb(167, 58, 58);color: white;}#borderBlue {border: 2px solid rgb(44, 67, 167);}
</style>
渲染结果:
<button class="redBack" id="btnBorderBlue">我是一个普通按钮</button>
2. 绑定class和style属性
class
和 style
可以和其他属性一样使用 v-bind
将它们和动态的字符串绑定;但是,在处理比较复杂的绑定时,通过拼接生成字符串是麻烦且易出错的;因此, Vue
专门为 class
和 style
的 v-bind
用法提供了特殊的功能增强;除了字符串外,表达式的值也可以是对象或数组。
class属性绑定
绑定对象
// 组合式
<script setup>import { ref, reactive } from 'vue'let btnClassObject = reactive({error: false, // 主题色flat: false // 阴影
})let capsule = ref(false)// 胶囊
let block = ref(false)// 块</script><template><input type="checkbox" v-model="btnClassObject.error"> error<input type="checkbox" v-model="btnClassObject.flat"> flat<br><br><button :class="btnClassObject">我是一个普通的按钮</button><hr><input type="checkbox" v-model="capsule"> 胶囊<input type="checkbox" v-model="block"> 块<br><br><button :class="{ 'rounded': capsule, 'fullWidth': block }">我是一个普通的按钮</button></template><style>
button {border: none;padding: 15px 20px;background-color: rgb(179, 175, 175);
}.error {background-color: rgb(167, 58, 58);color: white;
}.flat {box-shadow: 0 0 8px gray;
}.rounded {border-radius: 100px;
}.fullWidth {width: 100%;
}
</style>
绑定数组
// 组合式
<script setup>import { ref, reactive } from 'vue'let btnTheme = ref([]) // 按钮class数组let capsule = ref(false)// 胶囊
let widthTheme = ref([])// 宽度数组</script><template><input type="checkbox" value="error" v-model="btnTheme"> error<input type="checkbox" value="flat" v-model="btnTheme"> flat<br><br><!-- 直接使用数组数据源,数组中有哪些值,直接在该元素的class里出现对应的类名 --><button :class="btnTheme">我是一个普通的按钮</button><hr><input type="checkbox" v-model="capsule"> 胶囊<input type="checkbox" value="fullWidth" v-model="widthTheme"> 块<br><br><!-- 数组和对象一起使用 --><button :class="[{ 'rounded': capsule }, widthTheme]">我是一个普通的按钮</button></template><style>
button {border: none;padding: 15px 20px;background-color: rgb(179, 175, 175);
}.error {background-color: rgb(167, 58, 58);color: white;
}.flat {box-shadow: 0 0 8px gray;
}.rounded {border-radius: 100px;
}.fullWidth {width: 100%;
}
</style>
style属性绑定
绑定对象
// 组合式
<script setup>import { reactive, ref } from 'vue'let btnTheme = reactive({backgroundColor: '#FF0000', // 背景色color: '#000000' // 文本色
})let backColor = ref('#0000FF') // 背景色
let color = ref('#FFFFFF') // 文本色
let borRadius = ref(20) // 边框圆角</script><template>背景色:<input type="color" v-model="btnTheme.backgroundColor">文本色:<input type="color" v-model="btnTheme.color"><br><br><!-- style:可以直接绑定对象数据源,但是对象数据源的属性名当样式属性(驼峰命名法,kebab-cased形式) --><button :style="btnTheme">我是一个普通的按钮</button><hr>背景色:<input type="color" v-model="backColor">文本色:<input type="color" v-model="color">边框圆角:<input type="range" min="0" max="20" v-model="borRadius"><br><br><!-- style:可以直接写对象,但是对象的属性名当样式属性(驼峰命名法,kebab-cased形式) --><button :style="{backgroundColor: backColor,color,'border-radius': borRadius + 'px'}">我是一个普通的按钮</button></template><style>
button {border: none;padding: 15px 20px;background-color: rgb(179, 175, 175);
}
</style>
绑定数组
还可以给 :style
绑定一个包含多个样式对象的数组,这些对象会被合并后渲染到同一元素上
// 组合式
<!-- 脚本区域 -->
<script setup>
import { ref, reactive } from 'vue'const btnTheme = ref([{backgroundColor: '#FF0000', // 背景色color: '#FFFFFF' // 文本色},{borderRadius: 0 // 边框圆角}
])const colorTheme = reactive({backgroundColor: '#000000', // 背景色color: '#FFFFFF' // 文本色
})const radiusTheme = reactive({borderRadius: 0 // 边框圆角
})
</script><!-- 视图区域 -->
<template>背景色:<input type="color" v-model="btnTheme[0].backgroundColor">文本色:<input type="color" v-model="btnTheme[0].color">胶囊:<input type="checkbox" true-value="5px" false-value="0" v-model="btnTheme[1].borderRadius"><br><br><!-- 直接传入数组 --><button :style="btnTheme">我是一个普通按钮</button><hr>背景色:<input type="color" v-model="colorTheme.backgroundColor">文本色:<input type="color" v-model="colorTheme.color">胶囊:<input type="checkbox" true-value="5px" false-value="0" v-model="radiusTheme.borderRadius"><br><br><!-- 直接写数组 --><button :style="[colorTheme, radiusTheme]">我是一个普通按钮</button>
</template><style>
button {padding: 15px 20px;border: none;
}
</style>
五、条件渲染指令
1. v-if、v-else-if、v-else
v-if
指令用于条件性地渲染元素;该内容只会在指令的表达式返回真值时才被渲染v-else-if
提供的是相应于v-if
的else if
区块,它可以连续多次重复使用- 你也可以使用
v-else
为v-if
添加一个else
区块 v-else
和v-else-if
指令必须配合v-if
指令一起使用 ,否则它将不会被识别,而且语句块中间不能出现无关其他元素v-if
支持在<template>
元素上使用,这只是一个不可见的包装器元素,最后渲染的结果并不会包含这个<template>
元素
// 组合式
<script setup>import { ref } from 'vue'let isShow = ref(false) // 是否显示
let age = ref(20) // 年龄
let week = ref(3) // 周几</script><template>是否显示:<input type="checkbox" v-model="isShow"><!-- v-if:指令表达式为真时才会渲染该元素 为true时会创建该元素,为false时会销毁该元素--><h3 v-if="isShow">这是一个普通的标题标签</h3><hr>年龄: <input type="range" min="0" max="100" v-model="age"> {{ age }}<!-- v-if:可以配合 v-else-if 和 v-else 来搭建多重判断条件,他们中间不要参杂无关紧要的元素 --><h1 v-if="age < 18">未成年</h1><!-- <span>无关紧要的元素</span> --><h2 v-else-if="age < 35">青年</h2><h3 v-else-if="age < 50">中年</h3><h4 v-else>老年</h4><hr>周几: <input type="range" min="1" max="7" v-model="week"> {{ week }}<!-- v-if:可以配合 template 元素使用,最后渲染的结果并不会包含这个 <template>元素 --><template v-if="week == 1 || week == 3 || week == 5 || week == 7"><h1>可以游泳</h1></template><template v-else><h1>不可以游泳</h1></template></template>
2. v-show
v-show
按条件显示一个元素的指令v-show
会在DOM
渲染中保留该元素v-show
仅切换了该元素上名为display
的CSS
属性v-show
不支持在<template>
元素上使用,也不能和v-else
搭配使用
// 组合式
<script setup>import { ref } from 'vue'let isShow = ref(false) // 是否显示
let age = ref(20) // 年龄
let week = ref(3) // 周几</script><template>是否显示:<input type="checkbox" v-model="isShow"><!-- v-show:指令表达式为真时才会渲染该元素 无论该指令的表达式是否 true 或 false,该元素在元素中是保留该元素的为 true 时会删除该元素的 display:none 样式,为 false 时会给该元素添加 display:none 样式--><h3 v-show="isShow">这是一个普通的标题标签</h3><hr>年龄: <input type="range" min="0" max="100" v-model="age"> {{ age }}<h1 v-show="age < 18">未成年</h1><h2 v-show="age >= 18 && age < 35">青年</h2><h3 v-show="age >= 35 && age < 50">中年</h3><h4 v-show="age >= 50">老年</h4><hr>周几: <input type="range" min="1" max="7" v-model="week"> {{ week }}<!-- v-show:不可以配合 template 元素使用 --><!-- <template v-show="week == 1 || week == 3 || week == 5 || week == 7"><h1>可以游泳</h1></template><template v-shw="week == 12 || week == 4 || week == 6"><h1>不可以游泳</h1></template> --></template>
3. v-if和v-show的区别
v-if
是“真实的”按条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建v-if
也是惰性的:如果在初次渲染时条件值为false
,则不会做任何事;条件区块只有当条件首次变为true
时才被渲染v-show
元素无论初始条件如何,始终会被渲染,只有 CSSdisplay
属性会被切换v-if
有更高的切换开销,而v-show
有更高的初始渲染开销;如果需要频繁切换,则使用v-show
较好;如果在运行时绑定条件很少改变,则v-if
会更合适
六、事件绑定指令
我们可以使用 v-on:
指令 (简写为@) 来监听 DOM
事件,并在事件触发时执行对应的 JavaScript
用法:v-on:click=""
或 @click=""
用法:
// 组合式
<script>
export default {data: () => ({volume: 5 // 音量[0, 10]}),methods: {// 添大音量addVolume() {// 如果音量没有在最高值,则添加音量if (this.volume !== 10) {this.volume++}},// 减小音量subVolume() {// 如果音量没有在最小值,则减小音量if (this.volume !== 0) {this.volume--}},// 设置音量setVolume(value) {// 判断音量是否在取值范围之间if (value >= 0 && value <= 10) {this.volume = value}}}
}
</script><template><h3>当前音量:{{ volume }}</h3><!-- v-on: 事件绑定 --><button v-on:click="addVolume">添加音量</button><button v-on:click="subVolume">减小音量</button><hr><!-- @ 是 v-on: 的缩写 --><button @click="setVolume(0)">静音</button><button @click="setVolume(5)">音量适中</button><button @click="setVolume(10)">音量最大</button></template>
1. 事件修饰符
事件修饰符 | 说明 |
---|---|
.prevent | 阻止默认行为 |
.stop | 阻止事件冒泡 |
.capture | 以捕获模式触发当前的事件处理函数 |
.once | 绑定的事件只触发1次 |
.self | 只有在event.target是当前元素自身时触发事件处理函数 |
.passive | 向浏览器表明了不想阻止事件的默认行为 |
.prevent
.prevent
:阻止该事件的默认行为
// 组合式
<script setup>// 打招呼
function say(name) {window.alert('你好:' + name)
}</script><template><!-- .prevent 修饰符阻止了超链接的默认行为(跳转到百度页) --><a href="http://www.baidu.com" @click.prevent="say('baiDu')">百度</a></template>
.stop
.stop
:阻止事件产生的冒泡现象
// 组合式
<script setup>
// 打招呼
function say(name) {console.log('你好:' + name)
}
</script><template><div class="divArea" @click="say('DIV')"><!-- .stop:阻止产生冒泡事件 --><button @click.stop="say('BUTTON')">冒泡按钮</button></div>
</template><style>
.divArea {padding: 30px;border: 2px solid blue;
}
</style>
.once
.once
:绑定的事件只触发 1
次
// 组合式
<script setup>
// 打招呼
function say(name) {window.alert('你好:' + name)
}
</script><template><!-- .once:绑定的事件只触发一次 --><button @click.once="say('BUTTON')">点我试一下</button>
</template>
.self
.self
:只有在 event.target
是当前元素自身时触发事件处理函数
// 组合式
<script setup>
// 打招呼
function say(name) {window.alert('你好:' + name)
}
</script><template><!-- .self:只在该元素上触发事件有效,其子元素无效 --><div class="divArea" @click.self="say('DIV')"><button>我是一普通的按钮</button></div>
</template><style>
.divArea {padding: 30px;border: 2px solid blue;
}
</style>
.capture
.capture
给元素添加一个监听器
- 当元素事件产生冒泡时,先触发的是该修饰符的元素的事件
- 如果有多个该修饰符,则由外向内依次触发
// 组合式
<script setup>
// 打招呼
function say(name) {console.log('你好:' + name)
}
</script><template><!-- .capture 给元素添加一个监听器1:当元素事件产生冒泡时,先触发的是该修饰符的元素的事件2:如果有多个该修饰符,则由外向内依次触发--><div class="divArea" @click.capture="say('DIV-1')"><div class="divArea" @click="say('DIV-2')"><div class="divArea" @click.capture="say('DIV-3')"><button>我是一普通的按钮</button></div></div></div>
</template><style>
.divArea {padding: 30px;border: 2px solid blue;
}
</style>
.passive
.passive
:不阻止事件的默认行为,与 .prevent
不要同时使用
// 组合式
<script setup>
function eventPrevent() {// 阻止事件默认行为event.preventDefault()
}
</script><template><!-- .passive:先执行默认行为,不考虑执行的代码中是否包含 event.preventDefault() --><a href="http://www.baidu.com" @click.passive="eventPrevent">百度</a>
</template>
2. 按键修饰符
按键别名:.enter
、.tab
、.esc
、.space
、.up
、.down
、.left
、.right
、.delete
(捕获 Delete
和 Backspace
两个按键)
系统修饰符:.ctrl
、.alt
、.shift
、.meta
准确的修饰符:.exact
// 组合式
<script setup>
// 弹出消息
function showMessage(message) {window.alert(message)
}
</script><template>按下的键中包含 Enter 键事件: <input type="text" @keydown.enter="showMessage('你按下了 Enter 键')"><hr>按下的键中包含 Shift Enter 键事件:<input type="text" @keydown.enter.shift="showMessage('你按下了 Shift + Enter 键')"/><hr>按下的键只有 Shift Enter 键事件:<input type="text" @keydown.enter.shift.exact="showMessage('你只按下了 Shift + Enter 键')"/>
</template>
3. 鼠标按键修饰符
鼠标按键修饰符:.left
、.right
、.middle
// 组合式
<!-- 脚本区域 -->
<script setup>function showTest(text) {window.alert(text)}
</script><!-- 视图区域 -->
<template><!-- 鼠标右键按下 --><button @mousedown.right="showTest('按下的是鼠标右键')">鼠标右键按下</button><hr><!-- 点击时,采用的是鼠标中键 --><button @click.middle="showTest('按下的是鼠标中键')">点击时,采用的是鼠标中键</button><hr><!-- 鼠标左键按下 --><button @mousedown.left="showTest('按下的是鼠标左键')">鼠标左键按下</button>
</template><!-- 样式区域 -->
<style>button {border: none;padding: 15px 20px;}button:active {box-shadow: 0 0 5px grey;}
</style>
七、列表渲染指令
使用 v-for
指令基于一个数组来渲染一个列表
1. v-for渲染数组
语法:
in
前一个参数:item in items
item
:值
items
:需要循环的数组in
前两个参数:(value, index) in items
value
:值
index
:索引
items
:需要循环的数组
// 组合式
<script setup>
import { ref } from 'vue'
// 课程
let subject = ref([{ id: 1, name: 'Vue' },{ id: 2, name: 'Java' },{ id: 3, name: 'UI设计' },{ id: 4, name: 'Hadoop' },{ id: 5, name: '影视后期' },
])
</script><template><!-- item in itmesitem:值,当前循环的数组值itmes:循环的数组--><h6>v-for 渲染数组, v-for="item in itmes"</h6><ul><li v-for="sub in subject">编号:{{ sub.id }} --- 名称:{{ sub.name }}</li></ul><hr><!-- 解构对象 --><h6>v-for 渲染数组, v-for="{ 解构…… } in itmes"</h6><ul><li v-for="{ id , name } in subject">编号:{{ id }} --- 名称:{{ name }}</li></ul><hr><!-- (value, index) in itmesvalue:值index:索引itmes:循环的数组--><h6>v-for 渲染数组, v-for="(value, index) in itmes"</h6><ul><li v-for="(sub, index) in subject">编号:{{ sub.id }} --- 名称:{{ sub.name }} --- 索引:{{ index }}</li></ul><hr><!-- 解构对象 --><h6>v-for 渲染数组, v-for="({ 解构…… }, index) in itmes"</h6><ul><li v-for="({ id , name } , index) in subject">编号:{{ id }} --- 名称:{{ name }} --- 索引:{{ index }}</li></ul>
</template>
2. v-for渲染对象
使用 v-for
来遍历一个对象的所有属性,遍历的顺序会基于对该对象调用 Object.keys()
的返回值来决定
语法:
in
前一个参数:value in object
value
:属性值
items
:需要循环的对象in
前两个参数:(value, name) in object
value
:属性值
name
:键
items
:需要循环的对象in
前三个参数:(value, name, index) in object
value
:属性值
name
:键
index
:索引
items
:需要循环的对象
// 组合式
<script setup>
import { reactive } from 'vue'
let student = reactive({styNum: '007', // 学号name: 'Jack', // 名字age: 18 //年龄
})
</script><template><!-- value in objectvalue:属性值object:循环的对象--><h6>v-for 渲染对象, v-for="value in object"</h6><ul><li v-for="value in student">{{ value }}</li></ul><hr><!-- (value, name) in objectvalue:属性值name:属性名object:循环的对象--><h6>v-for 渲染对象, v-for="(value, name) in object"</h6><ul><li v-for="(value, name) in student">属性名:{{ name }} --- 属性值: {{ value }}</li></ul><hr><!-- (value, name, index) in objectvalue:属性值name:属性名index: 索引object:循环的对象--><h6>v-for 渲染对象, v-for="(value, name, index) in object"</h6><ul><li v-for="(value, name, index) in student">属性名:{{ name }} --- 属性值: {{ value }} --- 索引:{{ index }}</li></ul>
</template>
3. 通过 key 管理状态
当列表的数据变化时,默认情况下,vue
会尽可能的复用已存在的 DOM
元素,从而提升渲染的性能;但这种默认的性能优化策略,会导致有状态的列表无法被正确更新。
为了给 vue
一个提示,以便它能跟踪每个节点的身份,从而在保证有状态的列表被正确更新的前提下,提升渲染的性能;此时,需要为每项提供一个唯一的key属性:
key
的注意事项:
key
的类型只能是Number/String
key
值必须具有唯一性- 建议循环的列表有一个属性当
key
(该属性的值在此列表中唯一) - 不使用索引当
key
- 建议使用
v-for
指令时一定要指定key
的值
// 组合式
<script setup>
import { ref } from 'vue'
// 课程
let subject = ref([{ id: 1, name: 'Vue' },{ id: 2, name: 'Java' },{ id: 3, name: 'Hadoop' }
])// 添加课程
function addSubject() {// (数组最前面)添加subject.value.unshift({ id: 4, name: 'Python' })
}
</script><template><button @click.once="addSubject">添加课程(数组最前面)</button><h3>不使用key值</h3><ul><li v-for="sub in subject"><input type="checkbox">{{ sub }}</li></ul><hr><h3>使用索引当key值</h3><ul><li v-for="(sub, index) in subject" :key="index"><input type="checkbox">{{ sub }}</li></ul><hr><h3>使用列表属性当key值(该属性必须再此列表中唯一)</h3><ul><li v-for="sub in subject" :key="sub.id"><input type="checkbox">{{ sub }}</li></ul></template>
总结:
欢迎大家加入我的社区,在社区中会不定时发布一些精选内容:https://bbs.csdn.net/forums/db95ba6b828b43ababd4ee5e41e8d251?category=10003
以上就是 Vue3 中的模板语法,不懂得也可以在评论区里问我或私聊我询问,以后会持续发布一些新的功能,敬请关注。
我的其他文章:https://blog.csdn.net/weixin_62897746?type=blog
相关文章:

Vue3 中的模板语法
目录前言一、什么是模板语法?二、内容渲染指令1. v-text2. {{ }} 插值表达式3. v-html三、双向绑定指令1. v-model2. v-model的修饰符四、属性绑定指令1. 动态绑定多个属性值2. 绑定class和style属性五、条件渲染指令1. v-if、v-else-if、v-else2. v-show3. v-if和v…...

Redis十大类型——Hash常见操作
Redis十大类型——Hash常见操作命令操作简列存放及获取获取健值对长度元素查找列出健值对对数字进行操作赋值hsetnx很明显咯它也是以健值对方式存在的,只不过value也就是值,在这里也变成了一组简直对。 🍊个🌰: 想必多…...

Python采集本地二手房,一键知晓上万房源信息
前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 所以今天教大家用Python来采集本地房源数据,帮助大家筛选好房。 话不多说,让我们开始愉快的旅程吧~ 更多精彩内容、资源皆可点击文章下方名片获取此处跳转 本文涉及知识点 采集基本流程 requests 发送…...

Ubuntu 18.04 出现GLIBC_2.28 not found的解决方法(亲测有效)
关于/lib/x86_64-linux-gnu/libc.so.6: version GLIBC_2.28’ not found出现报错,建议不要使用源码包去编译并升级。在下文有分享一个使用官方的Debian软件包去升级使用的方法。仅供参考! 环境 # uname -a Linux Ubuntu 5.4.0-144-generic #161~18.04.…...

Java文档搜索引擎总结
Java文档搜索引擎总结项目介绍项目使用的技术栈前端页面展示后端逻辑部分索引部分搜索模块部分Web模块部分项目介绍 Java文档搜索引擎项目是一个SSM项目,该项目的前端界面部分是由搜索页面和展示页面组成,后端部分索引模块(ScanAnalysis、in…...

Linux内核学习笔记——页表的那些事。
目录页表什么时候创建内核页表变化什么时候更新到用户页表源码分析常见问题解答问题一:页表到底是保存在内核空间中还是用户空间中?问题2:页表访问,软件是不是会频繁陷入内核?问题3:内存申请,软…...

C++,Qt分别读写xml文件
XML语法 第一行是XML文档声明,<>内的代表是元素,基本语法如以下所示。C常见的是使用tiny库读写,Qt使用自带的库读写; <?xml version"1.0" encoding"utf-8" standalone"yes" ?> <根元素>…...

WebStorm安装教程【2023年最新版图解】一文教会你安装
文章目录引言一、下载WebStorm三、WebStorm激活配置及创建项目Active Code安装完成尝试新建一个项目引言 今天发现了一个专注前端开发的软件,相比VSCode的话,这个好像也不错,为了后续做个API接口项目做准备。 对于入门JavaScript 开发的者&am…...

用户态和内核态,系统调用
特权指令:具有特殊权限的指令,比如清内存,重置时钟,分配系统资源,修改用户的访问权限 由于这类指令的权限最大,所以使用不当会导致整个系统崩溃 系统调用:是操作系统提供给应用程序的接口(供应…...

Java 包装类
Java 中有些类只能操作对象,因此 Java 的基本数据类型都有一个对应的包装类。 byte:Byteshort:Shortint:Integerlong:Longfloat:Floatdouble:Doublechar:Characterbooleanÿ…...

Raspberry Pi GPIO入门指南
如果您想使用 Raspberry Pi 进行数字输入/输出操作,那么您需要使用 GPIO(通用输入/输出)引脚。在这篇文章中,我们将为您提供 Raspberry Pi GPIO 的基础知识,包括如何访问和操作 GPIO 引脚。 0.认识GPIO 树莓派上的那…...

汇编语言程序设计(三)之汇编程序
系列文章 汇编语言程序设计(一) 汇编语言程序设计(二)之寄存器 汇编程序 经过上述课程的学习,我们可以编写一个完整的程序了。这章开始我们将开始编写完整的汇编语言程序,用编译和连接程序将它们连接成可…...

用二极管和电容过滤电源波动,实现简单的稳压 - 小水泵升压改装方案
简而言之,就是类似采样保持电路,当电源电压因为电机启动而骤降时,用二极管避免电容电压跟着降低,从而让电容上连接的低功耗芯片有一个比较稳定的供电电压。没什么特别的用处,省个LDO 吧,电压跌幅太大的时候…...

【数据结构与算法】数据结构有哪些?算法有哪些?
1. 算法与数据结构总览图 2.常用的数据结构 2.1.数组(Array) 数组是一种聚合数据类型,它是将具有相同类型的若干变量有序地组织在一起的集合。数组可以说是最基本的数据结构,在各种编程语言中都有对应。一个数组可以分解为多个数…...

使用Element-UI展示数据(动态查询)
学习内容来源:视频P4 本篇文章进度接着之前的文章进行续写 精简前后端分离项目搭建 Vue基础容器使用 目录选择组件修改表格组件修改分页组件增加后端接口前端请求数据接口页面初始化请求数据点击页码请求数据选择组件 在官方文档中选择现成的组件,放在页…...

lamda 表达式例子全集
1、List 转 map 1.1、key(Model属性) value Model Map<String, Model> modeMap List.stream().collect(Collectors.toMap(Model1::属性get方法, v -> v, (p1, p2) -> p1)); 1.2、key(Model1属性) value Model2 Map<String, Model1> model2Map List.stream…...

计算机网络第八版——第一章课后题答案(超详细)
第一章 该答案为博主在网络上整理,排版不易,希望大家多多点赞支持。后续将会持续更新(可以给博主点个关注~ 【1-01】计算机网络可以向用户提供哪些服务? 解答:这道题没有现成的标准答案,因为可以从不同的…...

嵌入式和Python(二):python初识及其基本使用规则
目录 一,python基本特点 二,python使用说明 ● 两种编程方式 ① 交互式编程 ② 脚本式编程 ● python中文编码 ● python行和缩进 ● python引号 ● python空行 ● python等待用户输入 ① 没有转换变量类型 ② 转换变量类型 ● python变…...

C语言详解双向链表的基本操作
目录 双链表的定义与接口函数 定义双链表 接口函数 详解接口函数的实现 创建新节点(BuyLTNode) 初始化双链表(ListInit) 双向链表打印(ListPrint) 双链表查找(ListFind) 双链…...

面试必须要知道的常见排序算法
以下排序均为升序 1.直接插入排序 具体思想 把待排序的数据按大小比较插入到一个已经排序好的有序序列中,直到所有的待排序数据全部插入到有序序列中为止.实际生活中,我们平常斗地主摸牌时,就用到了插入排序的思想. 当插入第n个数据时,前面n-1个数据已经有序;第n个数据依次与前…...

Kubernetes之服务发布
学了服务发现后,svc的IP只能被集群内部主机及pod才可以访问,要想集群外的主机也可以访问svc,就需要利用到服务发布。 NodePort Nodeport服务是外部访问服务的最基本方式。当我们创建一个服务的时候,把服务的端口映射到kubernete…...

【第二章】谭浩强C语言课后习题答案
1. 什么是算法?试从日常生活中找3个例子,描述它们的算法 算法:简而言之就是求解问题的步骤,对特定问题求解步骤的一种描述。 比如生活中的例子: 考大学首先填报志愿表、交报名费、拿到准考证、按时参加考试、收到录取通知书、按照日期到指定学校报到。 去北京听演唱会首先…...

PostgreSQL和PostGISWGS84和CGCS2000与GCJ02和BD09坐标系与之间互转
– 如果转换后结果为null,查看geom的srid是否为4326或者4490 WGS84转GCJ02 select geoc_wgs84togcj02(geom) from test_table GCJ02转WGS84 select geoc_gcj02towgs84(geom) from test_table WGS84转BD09 select geoc_wgs84tobd09(geom) from test_table BD09转WGS84 select …...

数据结构——链表讲解(2)
作者:几冬雪来 时间:2023年3月5日 内容:数据结构链表讲解 目录 前言: 剩余的链表应用: 1.查找: 2.改写数据: 3.在pos之前插入数据: 4.pos位置删除: 5.在pos的后…...

Elasticsearch:图片相似度搜索的 5 个技术组成部分
作者:Radovan Ondas,Bernhard Suhm 在本系列博文的第一部分中,我们介绍了图像相似度搜索,并回顾了一种可以降低复杂性并便于实施的高级架构。 此博客解释了实现图像相似性搜索应用程序所需的每个组件的基本概念和技术注意事项。 学…...

【CVPR2022】Class Re-Activation Maps for Weakly-Supervised Semantic Segmentation
论文标题:Class Re-Activation Maps for Weakly-Supervised Semantic Segmentation收录:CVPR 2022paper: https://arxiv.org/abs/2203.00962code: https://github.com/zhaozhengChen/ReCAM解读:https://zhuanlan.zhihu.com/p/478133151https:…...

PMP项目管理项目运行环境
目录1 概述2 事业环境因素和组织过程资产3 组织系统3.1 概述3.2 组织治理框架3.2.1 治理框架3.2.2 项目治理3.3 管理要素3.4 组织结构类型3.4.1 组织结构类型3.4.2 项目管理办公室1 概述 项目所处的环境可能对项目的开展产生有利或不利的影响,这些影响的两大主要来…...

Vue 3.0 渲染函数 【Vue3 从零开始】
Vue 推荐在绝大多数情况下使用模板来创建你的 HTML。然而在一些场景中,你真的需要 JavaScript 的完全编程的能力。这时你可以用渲染函数,它比模板更接近编译器。 让我们深入一个简单的例子,这个例子里 render 函数很实用。假设我们要生成一些…...

西电软件体系结构核心考点汇总(期末真题+核心考点)
文章目录前言一、历年真题二、核心考点汇总2.1 什么是软件体系架构?(软件体系结构的定义)2.2 架构风格优缺点2.3 质量属性2.4 质量评估前言 主要针对西安电子科技大学《软件体系结构》的核心考点进行汇总。 【期末期间总结资料如下】 针对西电计科院软件工程专业大三《软件体…...

SRS源码分析-SDP内容解析
前言 在学习SRS的RTC模块之前,首先来分析下SRS在将rtmp推流转成rtc流,通过浏览器拉取webrtc流场景下产生的SDP内容 SDP格式介绍 SDP数据是文本格式,由多个 <key><value> 表达式构成,<key>的值只能是一个字符…...