一、前言
学习完前面一章的内容,你基本就已经可以开始使用vue开发前端页面了。
本章内容为vue中的进阶语法,通过学习本章的语法内容,可以在一定程度上简化你的代码量、让你对vue框架理解的更加深入、学习使用一些更加高级的特性。
二、生命周期
如果你熟悉任何一门编程语言,我相信你对“生命周期”这个词并不陌生,它常常被用于描述语言中一个变量的存在范围。
vue中其实也差不多,只不过这里不再是变量,而是描述的“组件”。
前面我们就说过,vue是以组件为单位组织代码的,一个组件中就包含了html
、js
、css
三种代码。
那么既然是组件,那当它被其它组件使用的时候,就会出现一系列状态:被创建、被加载、被更新、被卸载。
官网有张图详细描述了一个组件的全过程:
看着似乎有点多,但实际上在大部分情况下,我们用到的并不多。
从上图看得出来,一个vue组件总共有7种主状态。
- 从渲染器遇到一个组件开始
- 到初始化可选
api
,该过程就有生命周期钩子setup
与beforeCreate
- 判断是否编译了这个模板(也就是vue组件),该过程有一个生命周期钩子
created
- 渲染创建以及插入DOM节点,这一过程有一个
beforeMount
生命周期钩子 - 挂载这个组件,也就是将这个组件正式放置到页面上,有一个
mounted
生命周期钩子 - 重渲染修补状态,也就是当你更改组件中的标签内容时,有两个生命周期钩子:
beforeUpdate
、updated
- 卸载组件,也就是从页面上删除这个组件,有两个生命周期钩子:
beforeUnmount
、unmounted
上面主要是理了一下这张图的逻辑,也就是你只需要看中间的部分就可以了,一个组件从被创建直到销毁,总共有7种状态。
然后这些组件状态在切换时,官方就提供了一些钩子函数,可以让我们在其中做一些事情。
所谓钩子函数,就是将这个函数挂在指定为位置,当满足条件后,这个函数就会被自动调用。
那么如何使用呢?这在vue3的组件化编程中很简单:
<script setup>
import { onMounted } from 'vue';
//当组件被挂载时调用
onMounted(()=>{
console.log('组件被挂载了!');
});
</script>
因为组件化编程中将所有功能都被封装成了单独的函数,所以你只需要在前面那些钩子函数名字添加一个on
即可从vue中导出对应的生命周期钩子函数。
比如上面我就导出了一个最常用的钩子函数onMounted
,即图中mounted
生命周期钩子所在处。
为什么常用呢?因为它所处的位置刚好是DOM节点被创建且初始化之后被调用的。
DOM节点应该知道吧?形象的来说,就是你看到的
div
那些标签。
也就是说,如果我们想要初始化一下数据到页面上,那就必须要得等DOM初始化完成,而这个钩子函数所处的位置就刚刚好。
比如还有beforeMount
,其对应的函数就是onBeforeMount
,它就是在DOM初始化之前被调用,如果你在这个钩子函数中试图操作DOM节点,那么必然会报错。
如何操作?比如使用js中的
queryselect
等函数来查询节点,又或者使用vue中的ref
变量绑定节点。这就是在操作节点。
其它都是类似的意思,这里就不再过多赘述了。
其使用方式就是向这些钩子函数中传入一个函数作为参数,之后这个函数就会在相应的时间节点被调用。
实际上,我们这里的script
标签上的setup
属性,就是前面图中的那个setup
,只不过官方给我们简化了的。
如果你不写这个setup
,那么其实也等价于下面这种代码:
<script>
import { onMounted} from 'vue';
export default {
setup(msg) {
const msg=ref('这是一个ref变量');
onMounted(() => {
console.log('组件被挂载了!');
});
},
};
</script>
可以看到,如果不用这个语法糖,代肉眼可见的变得复杂起来了。
因为我们所有的函数、变量都要写入export default{}
中的setup
函数中。
三、数据双向绑定
前面我们已经使用过属性绑定,会发现那真的很有用,可以实现动态修改标签属性的目的。
但那也只能实现变量到标签属性的单方向绑定,也就是只能通过变量的变化,然后反映到标签上。
而有时候我们也需要动态将标签属性的变化反应到变量上,最常见的就是input
标签,它有一个value
属性代表当前标签内部用户输入的值。
很多时候我们都是需要在用户输入内容后获取这个值的,如果是以前,我们只能通过js
代码来获取这个属性值,但现在vue也给我们提供了方便语法,可以快捷实现这一功能。
vue提供了我们一个叫做v-model
的指令就可以实现属性与变量双向绑定的功能:
<script setup>
import { ref } from 'vue';
const val=ref();
</script>
<template>
<input type="text" v-model="val">
</template>
使用方式并不难,你只需要使用vue提供的v-model
指令让其等于一个响应式变量,就实现了双向绑定。
具体实现的效果就是,一旦你修改了响应式变量的值,input
控件中的显示内容会实时发生变化。
同时当用户修改input
变量中的值时,该响应式变量中的值也会实时变化,这便是双向绑定。
同时由于它默认会自动绑定标签中的value
属性,所以无需你去指定。
甚至你还可以为它添加修饰符,就像前面的事件处理那样:
<input type="text" v-model.number="val">
共有三个修饰符:
-
lazy
:默认情况下,v-model
会在每次input
事件后更新数据。你可以添加lazy
修饰符来改为在每次change
事件后更新数据: -
number
:让用户输入自动转换为数字 -
trim
:默认自动去除用户输入内容中两端的空格
除了input
标签外,双向绑定的用法还可以用在其它“表单”标签上。
比如文本输入框也可以绑定:
<textarea v-model="val"></textarea>
还有复选框:
<input type="checkbox" v-model="checked" />
如果有多个复选框,可以自动将其结果放在一个列表中:
<template>
<div>Checked names: {{ checkedNames }}</div>
<input type="checkbox" value="Jack" v-model="checkedNames">
<input type="checkbox" value="John" v-model="checkedNames">
<input type="checkbox" value="Mike" v-model="checkedNames">
</template>
<script setup>
import { ref } from 'vue';
const checkedNames=ref([]);
</script>
还有单选框:
<template>
<input type="radio" value="One" v-model="picked" />
<input type="radio" value="Two" v-model="picked" />
<div>{{ picked }}</div>
</template>
<script setup>
import { ref } from 'vue';
const picked=ref();
</script>
以及选择器:
<template>
<div>Selected: {{ selected }}</div>
<select v-model="selected">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
</template>
<script setup>
import { ref } from 'vue';
const selected=ref();
</script>
等等等等,更详细的内容可以查看官网介绍:表单输入绑定
四、计算属性
前面提到的模板语法提到过,模板中是可以写表达式的:
<template>
{{ msg.substring(0,msg.lastIndexOf('W')).toLocaleLowerCase() }}
</template>
但这样写太过于复杂了,你一眼很难看出这里最后的结果是什么。
所以后面我们用了一个函数来代替这个过程:
其实计算属性和上面这个方法目的差不多,就是为了简化模板语法中表达式的。
但居然官方要多出这么个“计算属性”,那想来肯定还是会有点不一样的,所以下面我们主要来看看如何使用计算属性、以及它与使用方法有什么区别。
它的使用方法也很简单,首先是引入computed这个方法。
import { computed } from 'vue';
这个方法接受一个函数,并返回一个对象,就像下面这样:
const process_msg=computed(()=>{
//处理其它步骤
return '返回最后的结果'
});
然后在你需要显示的地方,显示这个process_msg即可:
<template>
{{ process_msg }}
</template>
这和普通的方法非常的像,下面给一份完整代码:
<script setup>
import { ref,computed } from 'vue';
const msg="HELLO WORLD";
const process_msg=computed(()=>{
let pos=msg.lastIndexOf('W');
let sub=msg.substring(0,pos);
return sub.toLocaleLowerCase();
});
</script>
<template>
{{ process_msg }}
</template>
所以说实话,大部分情况下其实计算属性你都可以直接用方法替换,所以他们两者有什么区别呢?
两者唯一区别是计算属性会缓存,而方法不会。
举个例子,你有一个响应式的数组,划重点,一定要是响应式的:
reactive([1,2,3,4,5,6...])
假设该数组中有一万个元素,现在我分别写一个计算属性、一个方法来计算出该数组中所有元素的和。
那么区别就来了,使用方法时,只要你调用一次,那它就会循规蹈矩的计算一次。
而计算属性却不同,只要这个数组没有被更新过,那它就只计算第一次,并将第一次的结果存起来,一旦你下次使用就会直接返回上一次的计算结果,不会重新计算,这就是两者最显著的区别。
所以总的来说,如果能用计算属性,那还是尽量使用计算属性,毕竟人家官方专门弄出了这么个东西,肯定有它存在的道理。
除此之外官方文档还提到了一个计算属性修改变量的点,但正如官方自己所说,使用这个特性会引起警告,所以这里不再深入。
如果你非要改东西,那还不如用方法呢,毕竟现在计算机越来越快,只要别太离谱,也不会在意哪一点损耗了。