Vue开发尝试一下

1. provide传多个函数/属性

常规

js 复制代码
    // parent.vue
    const key = Symbol('sonContext')
    provide(key,{
        fn1:()=>{},
        fn2:()=>{}
    })
    // son.vue
    const context = inject(key)
    context?.fn1()

进阶

js 复制代码
// 封装成hook,调用方只关注传值即可,key在hook维护与组件解耦
import { inject, provide } from 'vue'
function useCreateProvide(key){
    // key也可以不传写死,每次调用都是最新的Symbol
    // const key = Symbol('provideKey')
    return [
        function useProvide(value){
            provide(key,value)
        },
        function useInject(defaultValue){
            return inject(key,defaultValue)
        }
    ]
}
const [useUserProvide,useUserInject] = createProvideState(Symbol('user'))
const [useSonProvide,useSonInject] = createProvideState(Symbol('son'))
export { useUserProvide, useUserInject, useSonProvide, useSonInject }

2.异步组件

  • 使用场景
js 复制代码
// 场景  组件从远程js获取 需要二次处理
import { h } from 'vue'
const items = [
    {type:'input',key:'name'},
    {url:'https://cdn.jsdelivr.net/npm/element-plus@2.10.4/es/components/affix/index.mjs'}
]
const Comp = {
  setup(_, { attrs, slots }) {
    const component = () =>
      defineAsyncComponent(() => {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            resolve({
              render() {
                return h('div', 'hello world')
              },
            })
          }, 1000)
        })
      })
    return h(component, attrs, slots)
  },
}
  • 简单实现一下低代码时远程获取组件
js 复制代码
const Comp = {
  props:['item'],
  setup(props){
    const component = ref(()=>return h('div',''))
    const url = props.item.url || 'https://unpkg.com/ant-design-vue/lib/index.js'
    const name = props.item.name || 'AButton'
    function loadScript(){
      import(url).then(module=>{
        const Comp = module[name]
        component.value = Comp
      })
    }
    loadScript()
    return h(component.value)
  }
}
  • 有了上面的基础来实现defineAsyncComponent
js 复制代码
//loader是个函数返回promise resove一个组件
function defineAsyncCompont(loader) {
  return {
    setup() {
      const componet = ref(() => h('span'))
        loader().then((res) => {
         // 处理一下 defineAsyncCompont(import('./Button.js'))
          if (res && res[Symbol.toStringTag] === 'module') {
            res = res.default
          }
          componet.value = res
        })
      return () => {
        return h(componet.value)
      }
    },
  }
}
  • 进阶(defineAsyncComponent接收对象可定义loader和loading error组件)
js 复制代码
import { h } from 'vue'
const Comp = {
  setup(_, { attrs, slots }) {
    const component = () =>
      defineAsyncComponent({
        loader: () => import('./ceshi.vue'),
        loadingComponent: {
            render(){
                return h('div','loading')
            }
        },
        errorComponent: () => import('./error.vue'),
      })
    return h(component, attrs, slots)
  },
}
  • 终极版实现异步组件
js 复制代码
export function defineAsyncComponent(options) {
  if (typeof options === 'function') {
    options = {
      loader: options,
    }
  }

  // 占位符组件
  const defaultComponent = () => h('span')

  const {
    loader,
    loadingComponent = defaultComponent,
    errorComponent = defaultComponent,
    timeout,
  } = options

  return {
    setup(_, { attrs, slots }) {
      const component = shallowRef(loadingComponent)

      function loadComponent() {
        return new Promise((resolve, reject) => {
          /**
           * 到点了,还没完成,我就调用 reject
           */
          if (timeout && timeout > 0) {
            setTimeout(() => {
              reject('超时了')
            }, timeout)
          }

          loader().then(resolve, reject)
        })
      }

      /**
       * loader 函数返回一个 Promise
       * 但是这个 Promise 我们不能控制它的成功和拒绝
       */
      loadComponent()
        .then((res) => {
          if (res && res[Symbol.toStringTag] === 'Module') {
            res = res.default
          }
          /**
           * 1000 ms 会进来
           */

          component.value = res
        })
        .catch(() => {
          // 组件加载失败了,改为 defaultComponent
          component.value = errorComponent
        })

      return () => {
        return h('div', [h(component.value, attrs, slots)])
      }
    },
  }
}
相关推荐
Cutecat_1 小时前
视频字幕处理工具横向:提取模式 vs 编辑模式,该如何选择
android·前端·ios·语音识别
qq_422152571 小时前
PDF 加水印工具怎么选?2026 年文档版权保护方案对比
前端·pdf·github
kyriewen1 小时前
手写 Promise.all、race、any:不到 30 行代码,解决并发异步的所有姿势
前端·javascript·面试
brucelee1862 小时前
OpenClaw 浏览器控制(Chrome MCP)完整教程
前端·chrome
ct9783 小时前
React 状态管理方案深度对比
开发语言·前端·react
胡志辉的博客3 小时前
深入浅出理解浏览器事件循环:从一道输出题讲到 Chrome 源码
前端·javascript·chrome·chromium·event loop
代码不加糖3 小时前
js中不会冒泡的事件有哪些?
前端·javascript·vue.js
懂懂tty3 小时前
Vue2与Vue3之间API差异
前端·javascript·vue.js
AI焦点3 小时前
跨越协议鸿沟:Tool Use状态机从Anthropic到OpenAI兼容体系的适配要点
前端·人工智能
Dxy12393102163 小时前
Python线程锁:为什么多线程会“打架“,以及怎么解决
开发语言·前端·python