【Vue3】Vue3手册
如果只想给页面添加一些简单的交互,可以使用 petite-vue,这是一个 Vue
的子集,只有 6kB 左右。
响应式
组件
渲染函数
渲染函数 & JSX
渲染函数 API
API 参考
全局属性
Vue2
中可以通过在 Vue.prototype
上添加属性实现全局访问。
// before - Vue 2
Vue.prototype.$http = () => {};
Vue3
中变更为 app.config.globalProperties
。
// after - Vue 3
const app = createApp({});
app.config.globalProperties.$http = () => {};
可直接在模板中使用,也可用 this
访问:
<template>
<div>{{ msg }}</div>
</template>
<script>
export default {
mounted() {
console.log(this.msg);
},
};
</script>
watch
- 二参的处理程序接收两个参数,一参为新值,二参为旧值,如果传入的是数组,返回值为:
(新值组,旧值组)
const x = ref(0);
const y = ref(0);
// 单个 ref
watch(x, (newX) => {
console.log(`x is ${newX}`);
});
// 多个来源组成的数组
watch([x, () => y.value], ([newX, newY], [oldX, oldY]) => {
console.log(`x is ${newX} and y is ${newY}`);
console.log(`oldx is ${oldX} and oldy is ${oldY}`);
});
- 监听响应式对象属性值时需要用
getter
函数包装:
const obj = reactive({ count: 0 });
// 错误,因为 watch() 得到的参数是一个 number
watch(obj.count, (count) => {
console.log(`count is: ${count}`);
});
// 提供一个 getter 函数
watch(
() => obj.count,
(count) => {
console.log(`count is: ${count}`);
}
);
deep 深层监听
直接给 watch()
传入一个响应式对象,会隐式地创建一个深层侦听器——该回调函数在所有嵌套的变更时都会被触发:
const obj = reactive({ count: 0 });
watch(obj, (newValue, oldValue) => {
// 在嵌套的属性变更时触发
// 注意:`newValue` 此处和 `oldValue` 是相等的
// 因为它们是同一个对象!
});
obj.count++;
- 一个返回响应式对象的
getter
函数只监听该响应式对象本身的变化,不会监听深层属性,相当于浅层监听,可使用deep
选项强制转为深层:
watch(
() => state.someObject,
(newValue, oldValue) => {
// 注意:`newValue` 此处和 `oldValue` 是相等的
// *除非* state.someObject 被整个替换了
},
{ deep: true }
);
watchEffect() 立即执行
在创建侦听器时立即执行一次。
watchPostEffect()
在 Vue 组件更新之后被调用(默认的侦听器回调函数都是在 Vue 组件更新之前调用,这意味着你在侦听器回调中访问的 DOM 将是更新之前的状态)。
也可以在其他创建侦听器方法中指明 flush: 'post'
选项以达到同样的效果:
watch(source, callback, {
flush: "post",
});
watchEffect(callback, {
flush: "post",
});
停止侦听器
同步创建的侦听器会在不需要时自动停止,异步创建的侦听器不会绑定到当前组件,需要手动停止。
创建侦听器方法的返回值就是停止侦听器函数:
import { watchEffect } from "vue";
// 异步侦听器不会自动停止
setTimeout(() => {
watchEffect(() => {});
}, 100);
const unwatch = watchEffect(() => {});
// ...当该侦听器不再需要时
unwatch();
ref 模板引用
为了通过组合式 API 获得该模板引用,我们需要声明一个同名的 ref:
<template>
<input ref="input" />
</template>
<script setup>
import { ref, onMounted } from "vue";
// 声明一个 ref 来存放该元素的引用
// 必须和模板里的 ref 同名
const input = ref(null);
onMounted(() => {
input.value.focus();
});
</script>
- 在
v-for
中使用模板引用时,对应的ref
包含的值是 DOM 数组,ref 数组并不保证与源数组相同的顺序。
组件的 ref
如果一个子组件使用的是选项式 API 或没有使用 <script setup>
,被引用的组件实例和该子组件的 this 完全一致,这意味着父组件对子组件的每一个属性和方法都有完全的访问权。
使用了 <script setup>
的组件是默认私有的:一个父组件无法访问到一个使用了 <script setup>
的子组件中的任何东西,除非子组件在其中通过 defineExpose()
方法显式暴露:
<script setup>
import {ref} from 'vue';
const a = 1;
const b = ref(2);
defineExpose({(a, b)})
</script>
v-for
v-for
可以使用解构方式定义:
<li v-for="{ message } in items">{{ message }}</li>
<!-- 有 index 索引时 -->
<li v-for="({ message }, index) in items">{{ message }} {{ index }}</li>
- 用
v-for
遍历数组时可以用of
来代替in
。 v-for
遍历对象时,遍历的顺序会基于对该对象调用Object.keys()
的返回值来决定。
v-model
Vue3
中的 v-model
与 Vue2
中的 .sync
行为相似,Vue3
中可指定多个 v-model
。
默认的 v-model
绑定的属性名与事件名为 modelValue
和 update:modelValue
。
组件内触发事件 $emit('update:modelValue')
实现数据的双向绑定。
<input v-model="searchText" />
<!-- 等价于 -->
<input :value="searchText" @input="searchText = $event.target.value" />
<!-- 在组件上使用时等价于 -->
<CustomInput
:modelValue="searchText"
@update:modelValue="newValue => searchText = newValue"
/>
绑定多个 v-model
:
<ChildComponent
v-model="modelValue"
v-model:title="pageTitle"
v-model:content="pageContent"
/>
<!-- 等价于 -->
<ChildComponent
:modelValue="modelValue"
@update:modelValue="modelValue = $event"
:title="pageTitle"
@update:title="pageTitle = $event"
:content="pageContent"
@update:content="pageContent = $event"
/>
<Teleport>
内置组件 <Teleport>
可以将组件内的 dom 渲染到指定的地方。
比如下面的页面结构,<comp1>
的内容会被渲染到 <main>
标签下:
<html>
<body>
<main>
<comp1></comp1>
</main>
</body>
</html>
但是如果在 <comp1>
组件中使用 <Teleport>
组件,就可以将内容渲染到 <body>
标签中:
<template>
<button @click="open = true">Open Modal</button>
<!-- Teleport 中的元素会被渲染到 body 中 -->
<Teleport to="body">
<div v-if="open" class="modal">
<p>Hello from the modal!</p>
<button @click="open = false">Close</button>
</div>
</Teleport>
</template>
生命周期钩子
Vue3
中的钩子函数需要主动引入。
beforeCreate -> setup
created -> setup
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
errorCaptured -> onErrorCaptured