学 vue3 通过官方文档更详细,不过阅读本博客,可以更容易理解,且帮你速成!
- 官方文档(记得将API风格偏好切换为
组合式
否则你学的是vue2)
https://cn.vuejs.org/guide/introduction.html
学习前的准备
-
创建一个 vue3 项目,详见链接
https://blog.csdn.net/weixin_41192489/article/details/128231728 -
开启 vue3 的实验性特征
在项目的 vite.config.ts 中添加
reactivityTransform: true,
-
添加 ts 对 vue3 实验性特征的支持
在项目的 tsconfig.json 中添加
"types": ["vue/ref-macros"]
改用 script setup
与 vue2 不同,vue3 的 js 代码写在 <script setup lang="ts">
中,如
<script setup lang="ts">
let count = $ref(0);
function increment() {
count++;
}
</script>
以下代码都在项目的 src\views\AboutView.vue 中测试,启动项目后,浏览器访问
http://127.0.0.1:5173/about 查看效果。
先将 AboutView.vue 初始化为
在这里插入代码片
定义响应式变量 $ref
vue2中写在 data(){} 函数中的变量,vue3中写法如下
// 定义响应式变量 count,初始值为 0
let count = $ref(0);
计算属性 computed
vue2中写在 computed 中的计算属性,vue3中写法如下
import { computed } from "vue";
let firstName = $ref("朝");
let lastName = $ref("阳");
// 当 firstName 或 lastName 变化时,会触发重新计算 fullName
let fullName = computed(() => {
return firstName + lastName;
});
- 计算属性中不能直接使用 reverse() 和 sort() ,因为这两个方法将变更原始数组,正确的用法是在调用这些方法之前创建一个原数组的副本
[...numbers]
return [...numbers].reverse()
实用技巧:动态绑定样式
<template>
<div>
<div :class="classObject">你好</div>
<button @click="bolder">加粗</button>
<button @click="markError">标红</button>
</div>
</template>
<script setup lang="ts">
import { computed } from "vue";
let isBold = $ref(false);
let error = $ref(false);
let classObject = computed(() => ({
bold: isBold,
"text-danger": error,
}));
function bolder() {
isBold = true;
}
function markError() {
error = true;
}
</script>
<style scoped>
.text-danger {
color: red;
}
.bold {
font-weight: bold;
}
</style>
定义方法 function
vue2中写在 methods 中的方法,vue3中写法如下
// 定义方法 increment,每执行一次,count 会自增 1
function increment() {
count++;
}
内联事件
逻辑极其简单的方法也可以直接写在元素上
<button @click="count++">增加1</button>
在方法后加 () 也会被视为内联事件
<button @click="increment()">增加1</button>
此时可以给方法添加参数
<button @click="increment('参数1',‘参数2’)">按指定参数增加</button>
内联事件访问原生 DOM 事件
需使用 $event
<button @click="submit('参数1', $event)">提交</button>
或者使用内联箭头函数
<button @click="(event) => submit('参数1', event)">提交</button>
方法事件
逻辑比较复杂时,则需给事件绑定方法
<button @click="show">展示</button>
此时方法的默认参数为原生 DOM 事件 event
// event 为原生 DOM 事件
function show(event: any) {
// 通过 event 可以获取事件相关的各种信息
console.log(event);
if (event) {
// 比如触发事件的标签名称
console.log(event.target.tagName);
}
}
事件修饰符
- .stop 禁止事件冒泡
<a @click.stop="doThis"></a>
效果同 event.stopPropagation()
- .prevent 禁止事件默认行为
效果同event.preventDefault()
使用范例:提交表单时不再重新加载页面
<form @submit.prevent="onSubmit"></form>
- .capture 事件采用捕获模式
指向内部元素的事件,在被内部元素处理前,先被外部处理
<div @click.capture="doThis">...</div>
- .passive 用于改善移动端设备的滚屏性能
一般用于触摸事件的监听器
范例:滚动事件的默认行为 (scrolling) 将立即发生而非等待 onScroll
完成,以防其中包含 event.preventDefault()
<div @scroll.passive="onScroll">...</div>
.passive 和 .prevent 不能同时使用,因为 .passive 已经向浏览器表明了你不想阻止事件的默认行为。如果同时使用,则 .prevent 会被忽略,并且浏览器会抛出警告。
还可以只使用修饰符,不绑定方法
<form @submit.prevent></form>
链式调用事件修饰符
<a @click.stop.prevent="show"></a>
但要注意调用顺序:
@click.prevent.self 阻止元素及其子元素的所有点击事件的默认行为
@click.self.prevent 只会阻止对元素本身的点击事件的默认行为。
常规按键修饰符
.按键名
即可实现指定按键触发事件
- 按键名的格式为 kebab-case 形式,如 PageDown 键需使用
.page-down
<!-- 按回车键时调用 submit -->
<input @keyup.enter="submit" />
<!-- 按 a 键时调用 submit -->
<input @keyup.a="submit" />
<!-- 按 PageDown 键时调用 submit -->
<input @keyup.page-down="submit" />
常用的按键有以下别名
- .enter
- .tab
- .delete (捕获“Delete”和“Backspace”两个按键)
- .esc
- .space
- .up
- .down
- .left
- .right
系统按键修饰符
- .ctrl
- .alt
- .shift
- .meta
在 Mac 键盘上,meta 是 Command 键 (⌘)。
在 Windows 键盘上,meta 键是 Windows 键 (⊞)。
系统按键修饰符与 keyup 事件一起使用时,该按键必须在事件发出时处于按下状态。如 keyup.ctrl
只会在你按住 ctrl 但松开另一个键时被触发,单独松开 ctrl 键将不会触发。
组合键的实现
<!-- Alt + Enter -->
<input @keyup.alt.enter="clear" />
<!-- Win + Enter
-->
<input @keyup.meta.enter="clear" />
<!-- Ctrl + 点击 -->
<div @click.ctrl="doSomething">Do something</div>
<!-- Ctrl + shift + a -->
<input @keyup.ctrl.shift.a="submit" />
.exact 修饰符
控制触发一个事件所需的确定组合
<!-- 当按下 Ctrl 时,即使同时按下 Alt 或 Shift 也会触发 -->
<button @click.ctrl="onClick">A</button>
<!-- 仅当按下 Ctrl 且未按任何其他键时才会触发 -->
<button @click.ctrl.exact="onCtrlClick">A</button>
<!-- 仅当没有按下任何系统按键时触发 -->
<button @click.exact="onClick">A</button>
鼠标按键修饰符
- .left
- .right
- .middle
<!-- 在该div上点击鼠标左键时触发 -->
<div @mousedown.left="submit">
条件渲染 v-if v-show
多个元素需要使用 v-if 控制渲染时,可以添加 <template>
包裹
<template v-if="showDetail">
<h1>标题</h1>
<p>段落一</p>
<p>段落二</p>
</template>
v-show 无法在 <template>
上使用
列表渲染 v-for
- 既可以用 in ,也可以用 of
<div v-for="item of items"></div>
- 可使用解构
const items = $ref([{ message: "1" }, { message: "2" }]);
<li v-for="({ message }, index) in items">{{ message }} {{ index }}</li>
- 渲染对象
<li v-for="(value, key, index) in myObject">
{{ index }}. {{ key }}: {{ value }}
</li>
- 渲染整数
效果为 1、2、3、…… n
<!-- n 的初值是从 1 开始而非 0 -->
<span v-for="n in 10">{{ n }}</span>
- 多个元素需要使用 v-for 渲染时,可以添加
<template>
包裹
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
此时 key 也要写在 <template>
上
<template v-for="todo in todos" :key="todo.name">
<li>{{ todo.name }}</li>
</template>
- key 需为字符串或 number 类型,不要用对象作为 key
v-if 和 v-for 同时存在于一个元素上时
v-if 会首先被执行,但不推荐这种写法
<ul>
<li
v-for="user in users"
v-if="user.isActive"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
应改用 <template>
包裹
<ul>
<template v-for="user in users" :key="user.id">
<li v-if="user.isActive">
{{ user.name }}
</li>
</template>
</ul>
双向绑定 v-model
v-model 绑定的值通常是静态的字符串 (复选框中是布尔值),使用 v-bind 可以将选项值绑定为非字符串的数据类型。
<select v-model="selected">
<!-- 内联对象字面量 -->
<option :value="{ number: 123 }">123</option>
</select>
单选按钮 radio
<div>Picked: {{ picked }}</div>
<input type="radio" id="one" value="One" v-model="picked" />
<label for="one">One</label>
<input type="radio" id="two" value="Two" v-model="picked" />
<label for="two">Two</label>
复选框 checkbox
单个复选框
<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>
默认值为 true 和 false
通过以下方法可以自定义值
<input
type="checkbox"
v-model="toggle"
true-value="yes"
false-value="no" />
true-value 和 false-value 是 Vue 特有的属性,仅支持和 v-model 配套使用
多个复选框——值为数组
const checkedNames = $ref([])
<div>Checked names: {{ checkedNames }}</div>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
自定义复选框
下拉单选 select
<div>Selected: {{ selected }}</div>
<select v-model="selected">
<option disabled value="">Please select one</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
v-model 的初始值不匹配任何一个选择项时,会渲染成一个“未选择”的状态。在 iOS 上,这将导致用户无法选择第一项,因为 iOS 在这种情况下不会触发 change 事件。因此,建议提供一个空值的禁用选项,如上例所示。
.lazy 修饰符
默认情况下,v-model 会在每次 input 事件后更新数据
.lazy 修饰符可以改为在每次 change 事件后更新数据
<!-- 在 "change" 事件后同步更新而不是 "input" -->
<input v-model.lazy="msg" />
.number 修饰符
让用户输入自动转换为数字
<input v-model.number="age" />
若该值无法被 parseFloat() 处理,则返回原始值。
number 修饰符会在输入框有 type=“number” 时自动启用。
.trim 修饰符
自动去除用户输入内容中两端的空格
<input v-model.trim="msg" />
父子组件
子组件继承样式
vue2 中限定只能有一个根节点,父组件中给子组件添加的样式,都会渲染在子组件的根节点上,如:
<!-- 子组件 -->
<p class="child">你好</p>
<!-- 父组件使用子组件时,添加了新的样式 father -->
<MyComponent class="father" />
最终渲染的效果为:
<p class="child father">你好</p>
vue3 中支持多个根节点,所以需要通过 $attrs
指定具体哪些节点继承父组件添加的样式。
<!-- 子组件:在需要继承样式的元素上,添加 :class="$attrs.class" -->
<p :class="$attrs.class">你好</p>
<span>我是朝阳</span>
<!-- 父组件使用子组件时,添加了新的样式 father -->
<MyComponent class="father" />
最终渲染的效果为:
<p class="father">你好</p>
<span>我是朝阳</span>