购物网站底部设计,非凡网站开发培训,招商网站平台,公司注册地址可以跨市迁移吗directive
定义#xff1a;本质就是一个 JavaScript 对象#xff0c;对象上挂着一些钩子函数。
实现#xff1a;在元素的生命周期中注入代码。
指令注册
注册原理#xff1a;把指令的定义保存到相应的地方#xff0c;未来使用的时候可以从保存的地方拿到。
全局注册与…directive
定义本质就是一个 JavaScript 对象对象上挂着一些钩子函数。
实现在元素的生命周期中注入代码。
指令注册
注册原理把指令的定义保存到相应的地方未来使用的时候可以从保存的地方拿到。
全局注册与局部注册的区别
全局注册存放在 instance.appContext 里局部注册存放在组件对象里
/*** 全局注册 app.directive*/
function createApp(rootComponent, rootProps null) {const context createAppContext()const app {_component: rootComponent,_props: rootProps,directive(name, directive) {// 检测指令名是否与内置的指令名有冲突if ((process.env.NODE_ENV ! production)) {validateDirectiveName(name)}// 没有第二个参数则获取对应的指令对象if (!directive) {return context.directives[name]}// 重复注册的警告if ((process.env.NODE_ENV ! production) context.directives[name]) {warn(/* ... */)}context.directives[name] directivereturn app}}return app
}指令解析
const DIRECTIVES directives;
/*** 解析指令 - 根据指令名称找到保存的指令的对象*/
function resolveDirective(name) {return resolveAsset(DIRECTIVES, name)
}/*** 解析资源*/
function resolveAsset(type, name, warnMissing true) {// 获取当前渲染实例const instance currentRenderingInstance || currentInstanceif (instance) {const Component instance.type// 先通过 resolve 函数解析局部注册的资源如果没有则解析全局注册的资源const res resolve(Component[type], name) || resolve(instance.appContext[type], name)// 如果没有则在非生产环境下报警告if ((process.env.NODE_ENV ! production) warnMissing !res) {warn(/* ... */)}return res} else if ((process.env.NODE_ENV ! production)) {warn(/* ... */)}
}/*** 解析*/
function resolve(registry, name) {// 先根据 name 匹配如果失败则把 name 转换成驼峰格式继续匹配如果失败则把 name 变为驼峰式后再首字母大写继续匹配return (registry (registry[name] || registry[camelize(name)] || registry[capitalize(camelize(name))]))
}/*** 绑定指令 - 给 vnode 添加一个 dirs 属性值为这个元素上所有指令构成的数组*/
function withDirectives(vnode, directives) {const internalInstance currentRenderingInstanceif (internalInstance null) {(process.env.NODE_ENV ! production) warn(/* ... */)return vnode}const instance internalInstance.proxyconst bindings vnode.dirs || (vnode.dirs [])// 遍历 directives拿到每一个指令对象以及指令的相关内容for (let i 0; i directives.length; i) {let [dir, value, arg, modifiers EMPTY_OBJ] directives[i]if (isFunction(dir)) {dir {mounted: dir,updated: dir}}bindings.push({dir, // 指令instance, // 组件实例value, // 指令值oldValue: void 0,arg, // 参数modifiers // 修饰符})}return vnode
}指令生命周期
挂载
/*** 挂载元素*/
const mountElement (vnode, container, anchor, parentComponent, parentSuspense, isSVG, optimized) {let elconst { type, props, shapeFlag, dirs } vnode// 创建 DOM 元素节点el vnode.el hostCreateElement(vnode.type, isSVG, props props.is)if (props) {// 处理 props比如 class、style、event 等属性}// 处理子节点是纯文本的情况if (shapeFlag 8/*TEXT_CHILDREN */) {hostSetElementText(el, vnode.children)}// 处理子节点是数组的情况挂载子节点else if (shapeFlag 16 /* ARRAY_CHILDREN*/) {mountChildren(vnode.children, el, null, parentComponent, parentSuspense, isSVG type ! foreignObject, optimized || !!vnode.dynamicChildren)// 在元素插入到容器之前会执行指令的 beforeMount 钩子函数if (dirs) {invokeDirectiveHook(vnode, null, parentComponent, beforeMount)}// 把创建的 DOM 元素节点挂载到 container 上hostInsert(el, container, anchor)// 在元素插入到容器之后会执行指令的 mounted 钩子函数 if (dirs) {// 通过 queuePostRenderEffect 进行包装目的是组件 render 后同步执行 mounted 钩子queuePostRenderEffect(() {invokeDirectiveHook(vnode, null, parentComponent, mounted)})}}
}/*** 执行指令 hook* param {Object} vnode - 新 vnode* param {Object} prevVNode - 旧 vnode* param {Object} instance - 组件实例* param {string} name - 钩子名称*/
function invokeDirectiveHook(vnode, prevVNode, instance, name) {const bindings vnode.dirsconst oldBindings prevVNode prevVNode.dirsfor (let i 0; i bindings.length; i) {const binding bindings[i]if (oldBindings) {binding.oldValue oldBindings[i].value}const hook binding.dir[name]if (hook) {callWithAsyncErrorHandling(hook, instance, 8/* DIRECTIVE_HOOK */, [vnode.el, binding, vnode, prevVNode])}}
}更新
/*** 组件更新*/
const patchElement (nl, n2, parentComponent, parentSuspense, isSVG, optimized) {const el (n2.el nl.el)const oldProps (n1 n1.props) || EMPTY_OBJconst newProps n2.props || EMPTY_OBJconst { dirs } n2// 更新 propspatchProps(el, n2, oldProps, newProps, parentComponent, parentSuspense, isSVG)const areChildrenSVG isSVG n2.type ! foreignObject// 在更新子节点之前会执行指令的 beforeUpdate 钩子if (dirs) {invokeDirectiveHook(n2, n1, parentComponent, beforeUpdate)}//更新子节点patchChildren(n1, n2, el, null, parentComponent, parentSuspense, areChildrenSVG)// 在更新子节点之后会执行指令的 updated 钩子if (dirs) {queuePostRenderEffect(() {invokeDirectiveHook(vnode, null, parentComponent, updated)})}
}卸载
/*** 组件卸载*/
const unmount (vnode, parentComponent, parentSuspense, doRemove false) {const { type, props, children, dynamicChildren, shapeFlag, patchFlag, dirs } vnodelet vnodeHookif ((vnodeHook props props.onVnodeBeforeUnmount)) {invokeVNodeHook(vnodeHook, parentComponent, vnode)}const shouldInvokeDirs shapeFlag 1/* ELEMENT */ dirsif (shapeFlag 6/* COMPONENT*/) {unmountComponent(vnode.component, parentSuspense, doRemove)} else {if (shapeFlag 128/* SUSPENSE */) {vnode.suspense.unmount(parentSuspense, doRemove)return}// 在移除元素的子节点之前执行指令的 beforeUnmount 钩子if (shouldInvokeDirs) {invokeDirectiveHook(vnode, null, parentComponent, beforeUnmount)}// 卸载子节点递归卸载自身节点和子节点if (dynamicChildren (type ! Fragment || (patchFlag 0 patchFlag 64/* STABLE_FRAGMENT */))) {unmountChildren(dynamicChildren, parentComponent, parentSuspense)} else if (shapeFlag 16/* ARRAY_CHILDREN */) {unmountChildren(children, parentComponent, parentSuspense)}if (shapeFlag 64/* TELEPORT */) {vnode.type.remove(vnode, internals)}// 移除自身节点if (doRemove) {remove(vnode)}}if ((vnodeHook props props.onVnodeUnmounted) || shouldInvokeDirs) {queuePostRenderEffect(() {vnodeHook invokeVNodeHook(vnodeHook, parentComponent, vnode)// 在移除元素的子节点之后执行指令的 unmounted 钩子if (shouldInvokeDirs) {invokeDirectiveHook(vnode, null, parentComponent, unmounted)}}, parentSuspense)}
}