- 其他
- 在 props/emits 选项中设置了的,都不会再出现在 $attrs 中。
inheritAttrs: false 设置后,所有属性都不会在根节点上继承
- PropType 用于协助定义 props 以便支持 ts 类型提示
- getCurrentInstance 需要显示导出。是获取当前调用位置的实例。只能在 setup 或 生命周期内,其他地方无效。
- 在 this.xxx 上设置的内容,可以用 getCurrentInstance().ctx.xxx 获取
- composables 组合化思想类似 React 的 Hook 方式
- setup(props, ctx) 函数
props 对应外部传入的 props 属性,它是响应式的。所以不建议解构
context 包含 { root, parent, attrs, slots, emit, expose } 属性,类似 this
- 非响应式,可以用es6结构
- 只有 expose 出的才能在实例上访问到
- 需要将响应式的内容
return { ... }
- 在
beforeCreate 前被调用,无法访问 this
- 注意: setup 和 render 是可以同时使用的,但是要处理好数据
- 响应式系统 api / 工作集
- reactive 接收普通对象/Ref返回响应对像。
- 使用方式 js/模版 都一样,使用返回的
值.属性
- 可以包含计算属性
- 不能对返回值解构和展开,不然会失去响应式。可以通过
toRefs 解决
shallowReactive 只对数据第一层进行响应式化。(性能优化)
- 注意:
- 整体替换
obj = Object.assign(obj, {xxx})
- 内部调用的是 proxy
- ref 接收基础类型返回一个响应式值。(也支持对像类型)
- 内部将值指向单一属性
xxx.value 。js 操作时使用 xxx.value,模版直接使用 xxx
shallowRef/triggerRef 配合使用(性能优化)
- 注意:
- 如果把 ref 放入 reactive 中时,操作方式安正常对象方式。
- 如果把
refObj.value 赋值另一个值A,这时改变 refObj.value 的值并不会触发A的改变。因为之间是常量赋值。
- 对于基本类型调用的是 Object.defineProperty 而对象是 proxy
- unref 返回参数本身
- isRef 检查值是否为一个 ref 对象
- readonly 只读的响应式对象
- toRef/toRefs 将
reactive 的某一属性或整体转为 **ref **类型
- toRaw 获取响应式对象的原始数据,修改它不会触发刷新
- 模版 Refs
- 通过响应式 ref 与模版 ref 进行绑定。并且** return 出的名称**要与模版上的
ref 相同
- 注意:获取值需要在
onMounted 时,或者通过 watchEffect 监听获取
- 响应式 computed 和 watch
- computed 计算属性
- 它接受
()=>{}getter 函数,返回一个默认不可手动修改的 ref 对象。
- 也可以使用一个带有
get/set 函数的对象来创建可读写 ref 对象
- js 内使用也是
x.value方式
- watch(source, callback(prev, cur, onInvalidate), { immediate, deep }) 数据源可以是一个拥有返回值的
getter 函数
- 可以直接是
ref 传入时不用传入 ref.value
- 只想对
reactive 内某一个属性监听,传入个 getter 函数 () => state/state.count 或者使用 toRef(obj, 'key')
- 可以使用数组来同时侦听多个源
- 和 watchEffect 的区别:
- 懒执行副作用
- 需要更具体说明什么状态应该触发重新运行
- 可访问监听状态的变化的前后值
- watchEffect( (onInvalidate) => {} [, {flush: 'pre(default)/post/sync'}] ) 立即执行的监听函数
options.flush 的前/后/同步指的是在组件 update 时它触发的时机
- 清理副作用
onInvalidate() 函数的触发时机
- 重新执行时前触发。(可用于清理上一次的一些结果)
- 侦听器被停止/组件卸载时触发。
- 类似 React 的 useEffect 函数
- 注意
- watchEffect/watch 默认是组件卸载时自动停止,也可以调用_返回值_手动停止。停止方式
const stop = watchEffect(); stop();
- 依赖注入
provide 功能类似 2.x 的
- 需要显示导入,使用方式为
(name, value) 形式
- 也可用于函数的提供
inject 接受一个可选的的默认值作为_第二个参数_
- InjectionKey 是个
interface 用于把 provide/inject 两者关联起来,是定义用的继承自 symbol 。
- 需要从 vue 中引入
- 渲染函数 h
h 现在是作为全局导入的。可以在 render 选项中返回,也可以 setup 中已经函数形式返回(主要形式)
setup() {
return () => h('div', null, 'abc')
}
- h(tagName, {options}, []) 函数
- 属性更加扁平,静/动态 class/style 都合并了。其他属性也不再用单独的属性名。
- v-model:扩展为 modelValue 和 onUpdate:modelValue 方式在模板编译过程中。支持多个绑定
modelValue 为使用 v-model 的默认名称。如果自定义改为 v-model:title 名称,函数调用时也改为 update:title 就好。都需要 emits 中定义
props: ['abc'],
emits: ['update:modelValue/cname'],
render() {
return h(SomeComponent, {
modelValue: this.abc,
'onUpdate:modelValue/cname': value => this.$emit('update:modelValue/cname', value)
})
}
- v-on:以
on 开头使用驼峰写法,修饰符只有 .passive/capture/once 生效。其他的用等价函数去操作
- 插槽:API 形式获取和对象形式设置,两种形式都可以
- 使用
this.$slots.default/slotName({ ...data }) 。如果传递数据就是作用域插槽
- 对象形式更多用于给**子组件(本身还是一个组件)**传递内容的
- 注意:
Transition 组件插槽用对象形式设置
h(resolveComponent('cmpChild'), null, {
header: (props) => slots.header(props),
default: (props) => slots.default(props)
});
h('div', null, [
h('div', { class: 'cmp-header' }, slots.header({ text: 'header' })),
h('div', { class: 'cmp-body' }, slots.default({ text: 'body' })),
]);
- 使用组件:只需要对全局注册的组件使用
resolveComponent。而对于局部注册的却可以直接使用。
- 和 is 动态组件:使用
resolveDynamicComponent(name) 去生成一个
- 自定义指令:使用
resolveDirective 去生成指令,使用 withDirectives 去包裹 h 函数使用指令
- 内置组件:在模版中使用时会自动导入。但在
render 函数中需要显示的自行导入
- 生命周期
- 在
setup 内,改为函数调用方式
~~beforeCreate~~ -> 使用 setup()
~~created~~ -> 使用 setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
errorCaptured -> onErrorCaptured
- 新增
onRenderTracked/onRenderTriggered 调试钩子函数
- 新组件
- Teleport 将特定的 html 传送到 Dom 的任意位置。
- 有
to="cssSelecter" 属性传入 css 选择器,然后进内部的 html 放到该节点下
disabled 用于控制 teleport 的作用
- Suspense 异步内容展示
- 需要返回
promise 对像,支持 async/await 语法
- 支持两个插槽
default/fallback。加载时展示 fallback 中内容,最总展示 default 的内容
- 全局配置
- globalProperties 具体用法
app.config.globalProperties.xxx = 123
- 配合
getCurrentInstance() 函数在 setup 里获取实例(当前),类似之前的 this 对象 internalInstance.appContext.config.globalProperties.xxx
internalInstance.ctx 是当前实例,也就是 this
- 全局 API
createApp({ 组件选项对象, propsData }) 返回一个实例。原本挂在 Vue 上的全局方法/属性,现在要挂到这个返回值 app 上。类似 Vue.extend() 可用于创建组件实例
- app.mount(string | Element)
- app.unmount(string | Element) 卸载,对应之前的
$destroy()
nextTick 和之前一样
defineComponent 返回传递给它的对象。在创建组件时用,主要是用于类型推断。
defineAsyncComponent 创建异步组件,可支持 promise 对象
- 高级用法(配置加载中组件、错误组件等)和 2.0 的相似
resolveComponent(name) 解析组件
resolveDirective(name) 解析自定义指令,没找到返回 undefined
withDirectives(vnode[, [directive, value, arg, modifiers]]) 指令应用于 VNode。注意是二维数组。每个指令本身又是一个数组。
- useCssModule 允许在
setup 内访问 css 模块
- 单文件组件
- 顶层的绑定会被暴露给模板,包括 import 导入的内容。组件也是直接导入即可使用
- 自定义指令:必须是
vNameOfDirective 命名方式的一个对象
- 属性转 API 方式:
defineProps/defineEmits/defineExpose
- useSlots/useAttrs:是
$slots/$attrs 的 API 形式,返回 setupContext.slots 和 setupContext.attrs
- 注意:
- 不支持
inheritAttrs 属性只能通过 <script> 选项式 API 实现
- 不支持
render 选项,需要配合 <script> 使用
- 版本迁移内容
- 已经支持多根节点了
- 深度选择器
:deep(selecter)
- composables 组合化:mixin 建议改为函数的方式去处理。也可以将部分 util 也函数化。
- 指令的变化
- 生命周期更改为
created/beforeMount/mounted/beforeUpdate/updated/beforeUnmount/unmounted
- 在组件上使用,只对组件的根生效
- **attrs∗∗将包含所有attribute包括id/class/style/listeners 的属性
- 事件将是以
on 开头的属性
- 所有在 props 选项中设置的属性都不会出现在其中了
- 新增 emits 属性类似 props 来定义组件真正可触发的事件(可被 emit('eventName') 的)
- 选项中列出的事件不会被组件的根元素继承,也将从 $attrs 中移除。其他的都在根上当作原生事件触发,除非子组件设置了
inheritAttrs: false
$children 移除,改用 ref 来获取
on/once/$off 已弃用,可用 mitt 库代替
filters 移除,用方法调用或计算属性来替换
- 全局 app.component/directive/mixin/use 都相同
- Vue.config.ignoredElements -> app.config.compilerOptions.isCustomElement
- Vue.prototype -> app.config.globalProperties
- 渲染函数 API 看上面 渲染函数 章
- 过度的 class 名改变
- 改为
v-enter-from/v-enter-active/v-enter-to 和 v-leave-from/v-leave/active/v-leav-to
- 组件自定义
v-model:PropName 的实现,去除了 ~~.sync~~ 修饰。具体看上面 渲染函数 章
- 组件外部生命周期监听:@hook:updated -> @vnode-updated
- 自定义组件
- 注册和使用方式。由于在
setup 中不能使用 this 所以和之前有差
export const CTOAST_KEY = Symbol('c-toast');
export function useCToast(options = {}) {
return inject(CTOAST_KEY)(options);
};
CToast.install = (app) => {
app.component(_CToast.name, _CToast);
app.config.globalProperties.$ctoast = CToast;
app.provide(CTOAST_KEY, CToast);
};
let teleport = document.body;
if (options.teleport !== 'body') {
if (typeof options.teleport === 'string') {
teleport = document.querySelector(options.teleport);
} else {
teleport = options.teleport;
}
}
const root = document.createElement('div');
const app = createApp(CusComponent, options);
app.mount(root);
app.unmount();
const vm = createVNode(CusComponent, options);
render(vm, root);
document.body.appendChild(root);
- 由于 setup 需要用于返回 h 函数,内部暴露的信息需要使用 expose 或者如下
setup() {
expose({
open() {},
text: 'abc'
});
return () => h('div');
}
setup() {
getCurrentInstance().render = () => h('div');
return {
open() {},
text: 'abc'
}
}
- vue JSX 插件 链接
- 按照
@vue/babel-plugin-jsx 插件,配置 { plugins: ["@vue/babel-plugin-jsx"] }
- vue-router 使用
- 相关 API 只能在
setup 中使用
- 在组合式 API 内使用函数调用的形式。其他的使用
this.$route/$router
- 组件内守卫和组合式 API 一样的使用方式
useLink 函数配合 RouterLink 属性,可用函数形式获取参数。类似 v-slot API。
- scrollBehavior:返回对象改为
{ left, top }
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHashHistory("basePath"),
routes: [{
path: '/:patchMatch(.*)*',
redirect: '/not-found'
}]
});
router.beforeEach((to, from, next) => {});
app.use(router);
import { useRoute, useRouter, onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
setup() {
const route = useRoute();
const router = useRouter();
}
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
- vuex 使用
useStore 只能在 setup 中使用
- 使用组合函数,好像就不支持
mapXXX 函数了
import { createStore } from 'vuex'
const store = createStore({
state: {/.../},
getters: {},
mutations: {},
actions: {}
})
app.use(store)
import { useStore } from 'vuex'
setup() {
const store = useStore()
const count = computed(() => store.state.count)
const double = computed(() => store.getters.double)
const increment = () => store.commit('increment')
const asyncIncrement = () => store.dispatch('asyncIncrement')
this.$store.state.a.xxx;
this.$store.getters['a/isAdmin'];
this.$store.commit/dispatch('a/increment');
}