Vue3中的依赖注入与组件定义怎么实现


本篇内容主要讲解“Vue3中的依赖注入与组件定义怎么实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Vue3中的依赖注入与组件定义怎么实现”吧! 提供一个值,可以被后代组件注入。

functionprovide(key:InjectionKey|string,value:T):void

接收两个参数:要注入的 key,字符串或者 Symbol

exportinterfaceInjectionKeyextendsSymbol{}

对应注入的值与注册生命周期钩子的 API 类似,provide() 必须在组件的 setup() 阶段同步调用。注入一个由祖先组件或整个应用 (通过 app.provide()) 提供的值。

//没有默认值
functioninject(key:InjectionKey|string):T|undefined

//带有默认值
functioninject(key:InjectionKey|string,defaultValue:T):T

//使用工厂函数
functioninject(
key:InjectionKey|string,
defaultValue:()=>T,
treatDefaultAsFactory:true
):T

第一个参数是注入的 keyVue 会遍历父组件链,通过匹配 key 来确定所提供的值。如果父组件链上多个组件对同一个 key 提供了值,那么离得更近的组件将会“覆盖”链上更远的组件所提供的值。如果没有能通过 key 匹配到值,inject() 将返回 undefined,除非提供了一个默认值。第二个参数是可选的,即在没有匹配到 key 时使用的默认值。它也可以是一个工厂函数,用来返回某些创建起来比较复杂的值。如果默认值本身就是一个函数,那么你必须将 false 作为第三个参数传入,表明这个函数就是默认值,而不是一个工厂函数。

//provide

//inject

createInjectionState 源码 / createInjectionState 使用package/core/computedInject 源码

import{typeInjectionKey,inject,provide}from'vue-demi'

/**
*创建可以注入到组件中的全局状态
*/
exportfunctioncreateInjectionState,Return>(
composable:(...args:Arguments)=>Return
):readonly[
useProvidingState:(...args:Arguments)=>Return,
useInjectedState:()=>Return|undefined
]{
constkey:string|InjectionKey=Symbol('InjectionState')
constuseProvidingState=(...args:Arguments)=>{
conststate=composable(...args)
provide(key,state)
returnstate
}
constuseInjectedState=()=>inject(key)
return[useProvidingState,useInjectedState]
}

等待下一次 DOM 更新刷新的工具方法。

functionnextTick(callback?:()=>void):Promise

说明:当你在 Vue 中更改响应式状态时,最终的 DOM 更新并不是同步生效的,而是由 Vue 将它们缓存在一个队列中,直到下一个“tick”才一起执行。这样是为了确保每个组件无论发生多少状态改变,都仅执行一次更新。nextTick() 可以在状态改变后立即使用,以等待 DOM 更新完成。你可以传递一个回调函数作为参数,或者 await 返回的 Promise

ElCascaderPanel 源码

exportdefaultdefineComponent({免费云主机域名
......
constsyncMenuState=(
newCheckedNodes:CascaderNode[],
reserveExpandingState=true
)=>{
......
checkedNodes.value=newNodes
nextTick(scrollToExpandingNode)
}
constscrollToExpandingNode=()=>{
if(!isClient)return
menuList.value.forEach((menu)=>{
constmenuElement=menu?.$el
if(menuElement){
constcontainer=menuElement.querySelector(`.${ns.namespace.value}-scrollbar__wrap`)
constactiveNode=menuElement.querySelector(`.${ns.b('node')}.${ns.is('active')}`)||
menuElement.querySelector(`.${ns.b('node')}.in-active-path`)
scrollIntoView(container,activeNode)
}
})
}
......
})

useInfiniteScroll 源码

exportfunctionuseInfiniteScroll(
element:MaybeComputedRef
......
){
conststate=reactive(......)
watch(
()=>state.arrivedState[direction],
async(v)=>{
if(v){
constelem=resolveUnref(element)asElement
......
if(options.preserveScrollPosition&&elem){
nextTick(()=>{
elem.scrollTo({
top:elem.scrollHeight-previous.height,
left:elem.scrollWidth-previous.width,
})
})
}
}
}
)
}

当你需要在修改了某些数据后立即对 DOM 进行操作时,可以使用 nextTick 来确保 DOM 已经更新完毕。例如,在使用 $ref 获取元素时,需要确保元素已经被渲染才能够正确获取。在一些复杂页面中,有些组件可能会因为条件渲染或动态数据而频繁地变化。使用 nextTick 可以避免频繁地进行 DOM 操作,从而提高应用程序的性能。当需要在模板中访问某些计算属性或者监听器中的值时,也可以使用 nextTick 来确保这些值已经更新完毕。这样可以避免在视图中访问到旧值。总之,nextTick 是一个非常有用的 API,可以确保在正确的时机对 DOM 进行操作,避免出现一些不必要的问题,并且可以提高应用程序的性能。在定义 Vue 组件时提供类型推导的辅助函数。

functiondefineComponent(
component:ComponentOptions|ComponentOptions['setup']
):ComponentConstructor

第一个参数是一个组件选项对象。返回值将是该选项对象本身,因为该函数实际上在运行时没有任何操作,仅用于提供类型推导。注意返回值的类型有一点特别:它会是一个构造函数类型,它的实例类型是根据选项推断出的组件实例类型。这是为了能让该返回值在 TSX 中用作标签时提供类型推导支持。

constFoo=defineComponent(/*...*/)
//提取出一个组件的实例类型(与其选项中的this的类型等价)
typeFooInstance=InstanceType

参考:Vue3 – defineComponent 解决了什么?ConfigProvider 源码

import{defineComponent,renderSlot,watch}from'vue'
import{provideGlobalConfig}from'./hooks/use-global-config'
import{configProviderProps}from'./config-provider-props'
......
constConfigProvider=defineComponent({
name:'ElConfigProvider',
props:configProviderProps,

setup(props,{slots}){
......
},
})
exporttypeConfigProviderInstance=InstanceType

exportdefaultConfigProvider

因为 defineComponent() 是一个函数调用,所以它可能被某些构建工具认为会产生副作用,如 webpack。即使一个组件从未被使用,也有可能不被 tree-shake。为了告诉 webpack 这个函数调用可以被安全地 tree-shake,我们可以在函数调用之前添加一个 /_#**PURE**_/ 形式的注释:

exportdefault/*#__PURE__*/defineComponent(/*...*/)

请注意,如果你的项目中使用的是 Vite,就不需要这么做,因为 Rollup (Vite 底层使用的生产环境打包工具) 可以智能地确定 defineComponent() 实际上并没有副作用,所以无需手动注释。OnClickOutside 源码

import{defineComponent,h,ref}from'vue-demi'
import{onClickOutside}from'@vueuse/core'
importtype{RenderableComponent}from'../types'
importtype{OnClickOutsideOptions}from'.'
exportinterfaceOnClickOutsidePropsextendsRenderableComponent{
options?:OnClickOutsideOptions
}
exportconstOnClickOutside=/*#__PURE__*/defineComponent({
name:'OnClickOutside',
props:['as','options']asunknownasundefined,
emits:['trigger'],
setup(props,{slots,emit}){
......

return()=>{
if(slots.default)
returnh(props.as||'div',{ref:target},slots.default())
}
},
})

定义一个异步组件,它在运行时是懒加载的。参数可以是一个异步加载函数,或是对加载行为进行更具体定制的一个选项对象。

functiondefineAsyncComponent(
source:AsyncComponentLoader|AsyncComponentOptions
):Component
typeAsyncComponentLoader=()=>Promise
interfaceAsyncComponentOptions{
loader:AsyncComponentLoader
loadingComponent?:Component
errorComponent?:Component
delay?:number
timeout?:number
suspensible?:boolean
onError?:(
error:Error,
retry:()=>void,
fail:()=>void,
attempts:number
)=>any
}

ES 模块动态导入也会返回一个 Promise,所以多数情况下我们会将它和 defineAsyncComponent 搭配使用。类似 ViteWebpack 这样的构建工具也支持此语法 (并且会将它们作为打包时的代码分割点),因此我们也可以用它来导入 Vue 单文件组件。

defineAsyncComponent()使用场景:当你需要异步加载某些组件时,可以使用 defineAsyncComponent 来进行组件懒加载,这样可以提高应用程序的性能。在一些复杂页面中,有些组件可能只有在用户执行特定操作或进入特定页面时才会被使用到。使用 defineAsyncComponent 可以降低初始页面加载时的资源开销。当你需要动态地加载某些组件时,也可以使用 defineAsyncComponent。例如,在路由中根据不同的路径加载不同的组件。除 Vue3 之外,许多基于 Vue 3 的库和框架也开始使用 defineAsyncComponent 来实现组件的异步加载。例如:VitePress: Vite 的官方文档工具,使用 defineAsyncComponent 来实现文档页面的异步加载。Nuxt.js: 基于 Vue.js 的静态网站生成器,从版本 2.15 开始支持 defineAsyncComponentQuasar Framework: 基于 Vue.js 的 UI 框架,从版本 2.0 开始支持 defineAsyncComponentElement UI Plus: 基于 Vue 3 的 UI 库,使用 defineAsyncComponent 来实现组件的异步加载。总之,随着 Vue 3 的普及,越来越多的库和框架都开始使用 defineAsyncComponent 来提高应用程序的性能。这个方法和 defineComponent 接受的参数相同,不同的是会返回一个原生自定义元素类的构造器。

functiondefineCustomElement(
component:
|(ComponentOptions&{styles?:string[]})
|ComponentOptions['setup']
):{
new(props?:object):HTMLElement
}

除了常规的组件选项,defineCustomElement() 还支持一个特别的选项 styles,它应该是一个内联 CSS 字符串的数组,所提供的 CSS 会被注入到该元素的 shadow root 上。
返回值是一个可以通过 customElements.define() 注册的自定义元素构造器。

import{defineCustomElement}from'vue'
constMyVueElement=defineCustomElement({
/*组件选项*/
})
//注册自定义元素
customElements.define('my-vue-element',MyVueElement)

import{defineCustomElement}from'vue'

constMyVueElement=defineCustomElement({
//这里是同平常一样的Vue组件选项
props:{},
emits:{},
template:`...`,
//defineCustomElement特有的:注入进shadowroot的CSS
styles:[`/*inlinedcss*/`],
})
//注册自定义元素
//注册之后,所有此页面中的``标签
//都会被升级
customElements.define('my-vue-element',MyVueElement)
//你也可以编程式地实例化元素:
//(必须在注册之后)
document.body.appendChild(
newMyVueElement({
//初始化props(可选)
})
)
//组件使用

除了 Vue 3 之外,一些基于 Vue 3 的库和框架也开始使用 defineCustomElement 来将 Vue 组件打包成自定义元素供其他框架或纯 HTML 页面使用。例如:Ionic Framework: 基于 Web Components移动端 UI 框架,从版本 6 开始支持使用 defineCustomElementIonic 组件打包成自定义元素。LitElement: Google 推出的 Web Components 库,提供类似 Vue 的模板语法,并支持使用 defineCustomElementLitElement 组件打包成自定义元素。Stencil: 由 Ionic Team 开发的 Web Components 工具链,可以将任何框架的组件转换为自定义元素,并支持使用 defineCustomElement 直接将 Vue 组件打包成自定义元素。到此,相信大家对“Vue3中的依赖注入与组件定义怎么实现”有了更深的了解,不妨来实际操作一番吧!这里是百云主机网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

相关推荐: Redisson分布式信号量RSemaphore如何使用

本文小编为大家详细介绍“Redisson分布式信号量RSemaphore如何使用”,内容详细,步骤清晰,细节处理妥当,希望这篇“Redisson分布式信号量RSemaphore如何使用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。初…

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

(0)
打赏 微信扫一扫 微信扫一扫
上一篇 05/28 18:43
下一篇 05/28 18:48

相关推荐