hello,各位老铁,今天我们继续讲解VUE3.0的相关知识点,
走过路过不要错过,有钱的捧个钱场,没钱的捧个人场(点赞+关注),祝愿各位看官幸福美满一生!
废话不多说,我们开始课程吧,书接上文:【卷起来】VUE3.0教程-02-模板语法-CSDN博客
🍁响应式基础
🌾 声明响应式状态
在组合式 API 中,推荐使用 ref() 函数来声明响应式状态:
<script >
import {ref} from 'vue'
const count = ref(0)
</script>
ref() 接收参数,并将其包裹在一个带有 .value 属性的 ref 对象中返回:
<script >
import {ref} from 'vue'
const count = ref(0)
console.log(count)
console.log(count.value)
count.value++
console.log(count.value) // 1
</script>
要在组件模板中访问 ref,请从组件的 setup() 函数中声明并返回它们:
<template>
<p>总计数量:{{count}}</p>
</template>
<script >
import {ref} from 'vue'
export default{
setup(){
const count = ref(20)
return {
count
}
}
}
</script>
注意,在模板中使用 ref 时,我们不需要附加 .value。为了方便起见,当在模板中使用时,ref 会自动解包 。
上面可以简写成:
<template>
<p>总计数量:{{count}}</p>
</template>
<script setup>
import {ref} from 'vue'
const count = ref(20)
</script>
🍁 计算属性
🌾 基础示例
模板中的表达式虽然方便,但也只能用来做简单的操作。如果在模板中写太多逻辑,会让模板变得臃肿,难以维护。比如说,我们有这样一个包含嵌套数组的对象:
<script setup>
import { reactive } from 'vue';
const author = reactive({
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
})
</script>
我们想根据 author 是否已有一些书籍来展示不同的信息:
<p>Has published books:</p>
<span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>
这里的模板看起来有些复杂。我们必须认真看好一会儿才能明白它的计算依赖于 author.books。更重要的是,如果在模板中需要不止一次这样的计算,我们可不想将这样的代码在模板里重复好多遍。
因此我们推荐使用计算属性来描述依赖响应式状态的复杂逻辑。这是重构后的示例:
<template>
<p>Has published books:</p>
<span>{{ publishedBooksMessage }}</span>
</template>
<script setup>
import { reactive,computed } from 'vue';
const author = reactive({
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
})
// 一个计算属性 ref
const publishedBooksMessage = computed(() => {
return author.books.length > 0 ? 'Yes' : 'No'
})
</script>
我们在这里定义了一个计算属性 publishedBooksMessage。computed() 方法期望接收一个 getter 函数,返回值为一个计算属性 ref(引用)。和其他一般的 ref(引用) 类似,你可以通过 publishedBooksMessage.value 访问计算结果。计算属性 ref 也会在模板中自动解包,因此在模板表达式中引用时无需添加 .value。
Vue 的计算属性会自动追踪响应式依赖。它会检测到 publishedBooksMessage 依赖于 author.books,所以当 author.books 改变时,任何依赖于 publishedBooksMessage 的绑定都会同时更新。
🌾 计算属性用方法替代写法
你可能注意到我们在表达式中像这样调用一个函数也会获得和计算属性相同的结果:
template>
<p>Has published books:</p>
<span>{{ publishedBooksMessage }}</span>
<p>{{calculateBookMessage()}}</p>
<p>{{ now }}</p>
<p>{{ now_fun() }}</p>
</template>
<script setup>
import { reactive,computed } from 'vue';
const author = reactive({
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
})
// 一个计算属性 ref
const publishedBooksMessage = computed(() => {
return author.books.length > 0 ? 'Yes' : 'No'
})
function calculateBookMessage(){
return author.books.length>0?'Yes':'No'
}
const now = computed(()=> Date.now())
function now_fun(){
return Date.now()
}
</script>
从结果可以看出,两种方式可以展示相同的效果:
计算属性相对于方法来说,内部有缓存机制,效率更高,调试方便,因此推荐使用计算属性。
🍁 Class 与Style绑定
数据绑定的一个常见需求场景是操纵元素的 CSS class 列表和内联样式。因为 class 和 style 都是attribute,我们可以和其他 attribute 一样使用 v-bind 将它们和动态的字符串绑定。但是,在处理比较复杂的绑定时,通过拼接生成字符串是麻烦且易出错的。因此,Vue 专门为 class 和 style 的 v-bind 用法提供了特殊的功能增强。除了字符串外,表达式的值也可以是对象或数组。
🌾 绑定对象
我们可以给 :class (v-bind:class 的缩写) 传递一个对象来动态切换 class:
<template>
<div :class="{active:isActive}">唯我酒剑仙</div>
</template>
<script setup>
const isActive = true
</script>
<style>
.active{
color:red;
font-size:18px
}
</style>
上面的语法表示 active 是否存在取决于数据属性 isActive 的真假值。
此外,:class 指令也可以和一般的 class attribute 共存。举例来说,下面这样的状态:
<template>
<div class="static"
:class="{active:isActive,'text-danger':noActive}">唯我酒剑仙</div>
</template>
<script setup>
const isActive = true
const noActive = false
</script>
<style>
.active{
color:green;
font-size:18px
}
.text-danger{
color:red;
font-size: 20px;
}
</style>
当 isActive 或者 hasError 改变时,class 列表会随之更新。举例来说,如果 hasError 变为 true,class 列表也会变成 "static active text-danger"。
渲染的结果会是:
绑定的对象并不一定需要写成内联字面量的形式,也可以直接绑定一个对象:
<template>
<div :class="classObject">数风流人物,还看今朝</div>
</template>
<script setup>
import { reactive } from 'vue'
const classObject = reactive({
active: true,
'text-danger':false
});
</script>
<style>
.active{
color:green;
font-size:18px
}
.text-danger{
color:red;
font-size: 20px;
}
</style>
注意,使用这种绑定对象的方式,必须 import { reactive } from '@vue/reactivity' 否则会报reactive找不到的问题。
我们也可以绑定一个返回对象的计算属性。这是一个常见且很有用的技巧:
<template>
<div :class="classObject">数风流人物,还看今朝</div>
</template>
<script setup>
import {ref,reactive,computed} from 'vue'
const isActive =ref(true);
const error = ref(null);
const classObject = computed(()=>({
active:isActive.value && error.value,
'text-danger':!error.value
}))
</script>
<style>
.active{
color:green;
font-size:18px
}
.text-danger{
color:red;
font-size: 20px;
}
</style>
🌾 绑定数组
我们可以给 :class 绑定一个数组来渲染多个 CSS class:
<template>
<!-- 使用绑定数组的方式 -->
<div :class="[activeClass,errorClass]">数风流人物,还看今朝</div>
</template>
<script setup>
import {ref,computed} from 'vue'
const activeClass = ref('active')
const errorClass = ref('text-danger')
</script>
<style>
.active{
color:green;
font-size:18px
}
.text-danger{
color:red;
background-color: blue;
}
</style>
如果你也想在数组中有条件地渲染某个 class,你可以使用三元表达式:
<template>
<div :class="[activeClass,errorClass]">数风流人物,还看今朝</div>
<div :class="[isActive?activeClass:'',errorClass]"></div>
</template>
<script setup>
import {ref,computed} from 'vue'
const activeClass = ref('active')
const errorClass = ref('text-danger')
const isActive = ref(false)
</script>
<style>
.active{
color:green;
font-size:18px
}
.text-danger{
color:red;
background-color: blue;
}
</style>
errorClass 会一直存在,但 activeClass 只会在 isActive 为真时才存在。
然而,这可能在有多个依赖条件的 class 时会有些冗长。因此也可以在数组中嵌套对象:
<template>
<div :class="[activeClass,errorClass]">数风流人物,还看今朝</div>
<div :class="[isActive?activeClass:'',errorClass]">羞答答的玫瑰静悄悄的开</div>
<div :class="[{ active: isActive }, errorClass]">铁锅炖大鹅</div>
</template>
<script setup>
import {ref,computed} from 'vue'
const activeClass = ref('active')
const errorClass = ref('text-danger')
const isActive = ref(false)
</script>
<style>
.active{
color:green;
font-size:18px
}
.text-danger{
color:red;
background-color: blue;
}
</style>
🌾 绑定内联样式
:style 支持绑定 JavaScript 对象值,对应的是 HTML 元素的style属性:
<template>
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }">O(∩_∩)O哈哈</div>
</template>
<script setup>
import {ref,computed} from 'vue'
const activeColor = ref('red')
const fontSize = ref(30)
</script>
也可以直接绑定一个样式对象,这样可以使模板更加简洁:
<template>
<!-- 绑定对象写法 -->
<div :style="styleObject">强无敌</div>
</template>
<script setup>
import {ref,reactive} from 'vue'
const styleObject = reactive({
color:'red',
fontSize: '14px'
});
</script>
我们还可以给 :style 绑定一个包含多个样式对象的数组。这些对象会被合并后渲染到同一元素上:
<template>
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }">O(∩_∩)O哈哈</div>
<!-- 绑定对象写法 -->
<div :style="styleObject">强无敌</div>
<!-- 绑定数组 -->
<div :style="[styleObject,backObject]">兄弟抱一下</div>
</template>
<script setup>
import {ref,reactive} from 'vue'
const activeColor = ref('red')
const fontSize = ref(30)
const styleObject = reactive({
color:'red',
fontSize: '14px'
});
const backObject = reactive({
background:'green',
'font-weight':'bold'
});
</script>
🍁 条件渲染
🌾 v-if
v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回真值时才被渲染。
也可以使用 v-else 为 v-if 添加一个“else 区块”
一个 v-else 元素必须跟在一个 v-if 或者 v-else-if 元素后面,否则它将不会被识别。
<template>
<h1 v-if="have_money">有钱:星辰大海,诗和远方</h1>
<h1 v-else>没钱:老老实实打工</h1>
<button @click="have_money=!have_money">有钱吗?</button>
</template>
<script setup>
import {ref} from 'vue'
const have_money = ref(true)
</script>
显示效果:
🌾 v-else-if
v-else-if 顾名思义,v-else-if 提供的是相应于 v-if 的“else if 区块”。它可以连续多次重复使用:
<template>
<h1 v-if="have_money<4000">回家看小电影</h1>
<h1 v-else-if="have_money<6000">出去下个馆子</h1>
<h1 v-else-if="have_money<8000">约妹子看个电影</h1>
<h1 v-else-if="have_money<15000">约妹子唱歌KTV</h1>
<h1 v-else-if="have_money<20000">约妹子蹦个迪</h1>
<h1 v-else>想干啥就去干吧</h1>
</template>
<script setup>
import {ref} from 'vue'
const have_money = ref(50000)
</script>
和 v-else 类似,一个使用 v-else-if 的元素必须紧跟在一个 v-if 或一个 v-else-if 元素后面。(类比Java)
🌾 v-show
另一个可以用来按条件显示一个元素的指令是 v-show。其用法基本一样:
<template>
<h1 v-show="have_money<4000">回家看小电影</h1>
<h1 v-show="have_money<6000">出去下个馆子</h1>
<h1 v-show="have_money<8000">约妹子看个电影</h1>
<h1 v-show="have_money<15000">约妹子唱歌KTV</h1>
<h1 v-show="have_money<20000">约妹子蹦个迪</h1>
<h1 v-show="have_money>20000">想干啥就去干吧</h1>
</template>
<script setup>
import {ref} from 'vue'
const have_money = ref(5000)
</script>
展示效果:
不同之处在于 v-show 会在 DOM 渲染中保留该元素;v-show 仅切换了该元素上名为 display 的 CSS 属性。
🌾 v-if 和 v-show 对比
v-if 是“真实的”按条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建。
v-if 也是惰性的:如果在初次渲染时条件值为 false,则不会做任何事。条件区块只有当条件首次变为true 时才被渲染。
相比之下,v-show 简单许多,元素无论初始条件如何,始终会被渲染,只有 CSS display 属性会被切换。
总的来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要频繁切换,则使用 v-show 较好;如果在运行时绑定条件很少改变,则 v-if 会更合适。
🍁 列表渲染
🌾 v-for
我们可以使用 v-for 指令基于一个数组来渲染一个列表。v-for 指令的值需要使用 item in items 形式的特殊语法,其中 items 是源数据的数组,而 item 是迭代项的别名:
<template>
<h2>我的老婆们</h2>
<ul>
<li v-for="wife in wifes">
{{wife.name}}
</li>
</ul>
</template>
<script setup>
import {ref} from 'vue'
const wifes = ref([{name:'赵丽颖'},{name:'刘亦菲'},{name:'景甜'}])
</script>
在 v-for 块中可以完整地访问父作用域内的属性和变量。v-for 也支持使用可选的第二个参数表示当前项的位置索引。
<template>
<h2>我的老婆们</h2>
<ul>
<li v-for="wife in wifes">
{{wife.name}}
</li>
</ul>
<hr/>
<h2>我的老婆们</h2>
<ul>
<li v-for="(wife,index) in wifes">
{{my_love}}---{{index}}---{{wife.name}}
</li>
</ul>
</template>
<script setup>
import {ref} from 'vue'
const my_love = ref("我爱:")
const wifes = ref([{name:'赵丽颖'},{name:'刘亦菲'},{name:'景甜'}])
</script>
🌾 v-for 与对象
你也可以使用 v-for 来遍历一个对象的所有属性。遍历的顺序会基于对该对象调用 Object.keys() 的返回值来决定。
<template>
<p v-for="value in mywife">
{{ value }}
</p>
</template>
<script setup>
import {ref,reactive} from 'vue'
const mywife = reactive({
name:"刘亦菲",
age:18,
best_love:'攀哥'
});
</script>
可以通过提供第二个参数表示属性名 (例如 key):
<template>
<p v-for="(value,key) in mywife">
{{key}}:{{ value }}
</p>
</template>
<script setup>
import {ref,reactive} from 'vue'
const mywife = reactive({
name:"刘亦菲",
age:18,
best_love:'攀哥'
});
</script>
第三个参数表示位置索引:
<template>
<p v-for="(value,key,index) in mywife">
{{index+1}}. {{key}}:{{ value }}
</p>
</template>
<script setup>
import {ref,reactive} from 'vue'
const mywife = reactive({
name:"刘亦菲",
age:18,
best_love:'攀哥'
});
</script>
🌾 在 v-for 里使用范围值
v-for 可以直接接受一个整数值。在这种用例中,会将该模板基于 1...n 的取值范围重复多次。
<template>
<p v-for="n in 10">第{{n}}次说爱你</p>
</template>
<script setup>
</script>
注意此处 n 的初值是从 1 开始而非 0。
🌾 v-for 和 v-if
当它们同时存在于一个节点上时,v-if 比 v-for 的优先级更高。这意味着 v-if 的条件将无法访问到 v-for 作用域内定义的变量别名:
<template>
<!--
这会抛出一个错误,Cannot read properties of undefined (reading 'isComplete')
因为属性 todo 此时没有在该实例上定义
-->
<li v-for="todo in todos" v-if="!todo.isComplete">
{{ todo.name }}
</li>
</template>
<script setup>
import {ref} from 'vue'
const todos = ref([{name:'墨轩', isComplete:true},{name:'阿良', isComplete:false}])
</script>
运行后报错:
在外新包装一层<template>, 再在其上使用 v-for 可以解决这个问题 (这也更加明显易读):
<template>
<template v-for="todo in todos">
<li v-if="!todo.isComplete">
{{ todo.name }}
</li>
</template>
</template>
<script setup>
import {ref} from 'vue'
const todos = ref([{name:'墨轩', isComplete:true},{name:'阿良', isComplete:false}])
</script>
----------------------------------------------------------------------
分享不易,耗时耗力,喜欢的同学给个关注和赞吧
承接毕设指导,技术答疑,学习路上想要找私人教练的同学可以私信我
更多学习资料,公众号:墨轩学习网,B站:墨轩大楼
----------------------------------------------------------------------