dxf上一篇中的结尾我们讲了组件传递参数的两种参数,但是这些参数都是写死的。我们要如何才能使参数动态变化呢?这就进入到了Vue核心功能——响应式。
响应式数据
我们想要给博客预览组件添加一个新的功能:点赞和显示点赞数。首先我们需要一个点赞按钮和一个点赞函数(虽然不符合一般的博客逻辑,但是这里我们就先这么做了)。在一切的开始,我们需要给预览组件添加一个属性来表示点赞数。这里的属性不是一般的属性,而是Vue中可以进行双向绑定的属性。
在Vue3中,我们可以使用reactive函数来创建一个响应式对象。
<script setup>
import { reactive } from 'vue';
defineProps(['mainText']);
let state = reactive({like: 0});
function likeUp(){
state.like++;
}
</script>
但是reactive函数拥有自己的局限性。首先是因为其只能传入复杂数据类型,而对基本数据类型无能为力。其次,Vue响应式是通过属性访问器进行追踪的,也就是说如果使用重新定义的方式来进行属性修改的话,那么前后会被Vue视为两个响应式属性。因此下面的代码将不会起作用。
<script setup>
import { reactive } from 'vue';
defineProps(['mainText']);
let state = reactive({like: 0});
function likeUp(){
state = reactive({like:1})
}
</script>
如果要解决上述问题,我们可以使用ref函数代替reactive函数,就像下面这样。
<script setup>
import { ref } from 'vue';
defineProps(['mainText']);
let like = ref(0);
function likeUp(){
like.value++
}
</script>
v-on
你会想,这应该很简单,我们直接使用on-click属性不就可以了吗。是这样,但是Vue给我们了一个可以自定义事件的替代方案,也就是v-on指令。完整的博客点赞组件如下:
<script setup>
<script setup>
import { ref } from 'vue';
defineProps(['mainText']);
let like = ref(0);
function likeUp(){
like.value++
}
</script>
<template>
<div>
<slot/>
{{ mainText }}
<button @click="likeUp">点赞数:{{ like }}</button>
</div>
</template>
<style>
</style>
注意,通过ref函数创建的变量在JavaScript代码中被访问的话需要使用value(毕竟ref还承担着响应式的任务,不可能只有一个属性),而在template中则不需要,Vue会自动将其解包(当然这种解包并不会嵌套,只能解包一层)。
运行项目,我们会发现按钮在每次点击之后点赞数都会加一,说明我们成功地构建了响应式操作。其实@是v-on的简写,我们把@click改成v-on:click也可以达到同样的效果。
v-bind
回到App.vue,如果我们想通过JavaScript代码来控制博客预览中的正文,也就是通过JavaScript代码响应式地绑定元素的属性,应该怎么办?这就需要使用v-bind指令了。
<script setup>
import { ref } from 'vue';
import ArticlePreview from './components/ArticlePreview.vue';
let mainText= ref(0);
setTimeout(()=>{
mainText.value = 1;
},1000)
</script>
<template>
<header>
<img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" />
<ArticlePreview :main-text="mainText">1</ArticlePreview>
<ArticlePreview :main-text="mainText">2</ArticlePreview>
<div class="wrapper">
</div>
</header>
<main>
</main>
</template>
运行项目,会发现博客的正文在一秒钟后都从0变成了1。和上一个指令一样,:main-text也是简写,是v-bind:main-text的简写。
v-for
在真正的生产环境中,我们的博客列表一般都是一个可迭代的形式,比如数组。而且我们事先可能不知道数组的长度。那我们怎么样才能灵活控制博客预览元素的个数呢?这就需要用到v-for指令了。
<script setup>
import ArticlePreview from './components/ArticlePreview.vue';
let blogTitles = [1,2,3,4,5,6,7,8,9]
</script>
<template>
<header>
<img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" />
<div v-for="blogTitle in blogTitles">
<ArticlePreview>{{ blogTitle }}</ArticlePreview>
</div>
<div class="wrapper">
</div>
</header>
<main>
</main>
</template>