Vue3 封装第三方组件(一)做一个合格的传声筒

简介: 各种UI库的功能都是非常强大的,尤其对于我这种不会 css 的人来说,就更是帮了大忙了。

各种UI库的功能都是非常强大的,尤其对于我这种不会 css 的人来说,就更是帮了大忙了。

只是嘛,如果再封装一下的话,那么用起来就会更方便了。


那么如何封装呢?


封装三要素 —— 属性、插槽、事件、方法



可以封装,但是原生UI库提供的强大功能不能给封装没了吧,吃了回扣可是不好滴。 那么如何做到不遗漏呢?先做一个合格的传声筒。


传递属性



先看看 el-input 提供的属性:


image.png


太长了,这里只截了一半。 这么多的属性,如果一个一个都弄到 props 里面,然后再一个一个绑定上去,这就太麻烦了。


我们可以分成两部分,重要的属性做到 props 里面,其他的可以放到 $attrs 里面。


定义一个简单的组件


模板


<template>
  <div>
    <el-input
      v-model="value" // 不能直接帮的属性
      v-bind="$attrs"  // 绑定其他属性。
    >
    </el-input> 
  </div>
</template>
复制代码


代码


export default {
  name: 'test-text',
  inheritAttrs: false,
  props: {
    modelValue: [String, Number]
  },
  setup(props, ctx) {
    const value = debounceRef(props, ctx.emit)
    return {
      value
    }
  }
}
复制代码


父组件的调用代码: 模板


<inputtext
    v-model="value"
    v-bind="attrs"
  >
  </inputtext>
复制代码


代码


const value = ref('222')
const attrs = reactive({
  maxlength: 10,
  'show-word-limit': true,
  clearable: true
})
复制代码


这里 modelValue 就是 props ,maxlength、show-word-limit、clearable 就变成了 $attrs 。


然后要看 el-input 是否是根元素,如果是跟元素的话,那么会自动绑定上,不需要我们手动写 v-bind="$attrs"


如果像上面的例子不是根元素的话,需要手动写  v-bind="$attrs"


inheritAttrs


这个是指定组件是否自动绑定 attrs。默认是true,会自动把attrs 。 默认是 true,会自动把 attrstrueattrs 绑定到根元素上面,不管根元素是啥。 这里设置为 false,那么$attrs 就不会自动绑定到 div 上面了。


插槽



这个稍微复杂一点,插槽本来就有一点绕,官网的介绍又比较含混。


我们可以找到 $slots 这个东东,但是官网的介绍(www.vue3js.cn/docs/zh/api… )却是 使用 h,这个就……


不过想要传递插槽,还是需要这个。


我们先看看 el-input 的插槽的使用。


<el-input
    placeholder="请输入内容"
    v-model="input3"
    class="input-with-select"
  >
    <template #prepend>
      <el-select v-model="select" placeholder="请选择">
        <el-option label="餐厅名" value="1"></el-option>
        <el-option label="订单号" value="2"></el-option>
        <el-option label="用户电话" value="3"></el-option>
      </el-select>
    </template>
    <template #append>
      <el-button icon="el-icon-search"></el-button>
    </template>
  </el-input>
复制代码


那么想要传递插槽的话,是不是可以这样?


<!--传递插槽-->
    <template  v-slot:prepend> // 给递给el-input 的插槽
      <slot name="prepend"></slot> // 接收父组件传递进来的插槽
    </template> 
复制代码


测试可以。


那么总不会一个一个写吧,这也太麻烦了。如果能够for就好了。


等等, for?那么我们是不是可以这样。


<!--传递插槽-->
  <template 
    v-for="(item, key, index) in $slots"
      :key="index"
      v-slot:[key]
  >
      <slot :name="key"></slot>
  </template>  
复制代码


测试可以。


完整代码


<el-input
      ref="refInput"
      v-model="value"
      v-bind="$attrs"
    >
      <!--传递插槽-->
      <template 
        v-for="(item, key, index) in $slots"
        :key="index"
        v-slot:[key]
      >
        <slot :name="key"></slot>
      </template> 
    </el-input> 
复制代码


传递事件



这个就简单了,啥都不用做,自动就传递出去了。el-input 是否是跟元素都可以。 测试一下:


<inputtext
    ref="refInput"
    v-model="value"
    v-bind="props"
    @clear="clear"
    @my-change="myChange"
  >
复制代码


  • clear 是 el-input 提供的事件,外部可以直接得到这个事件,组件内部不用做操作。


  • my-change 是自定义的事件。


方法



一直都忽略了,还有方法这个事,因为基本没用过。


使用方法嘛,就需要使用 ref,这个此 ref 非彼 ref,说不清了,还是写代码吧。


直接使用的方法


直接使用UI库组件的方法,比如 el-input 的 提供的 select:


image.png


<el-input
  ref="refInput" // 注意这里的 ref 
  v-model="value"
  v-bind="$attrs" >
</el-input> 
复制代码


ref 的写法,不要加冒号。


const refInput = ref(null) // 先放一个null
onMounted(() => { // 然后在 onMounted 里面才能得到值。
  console.log('refinput', refInput) // 看看啥样。
  refInput.value.select() // 调用方法,文本框的内容会被选中
})
复制代码


先定义一个 ref,然后交给模板里的 ref,好像有点绕,这里必须使用 ref,reactive是不行滴。


在渲染后才能生效,也就是说必须在 onMounted 里面才能得到值,我们看看打印结果:(太长只能截取一部分)


image.png


很长吧。


父组件里面怎么用方法


<inputtext
    ref="refInput"
    v-model="value">
</el-input> 
复制代码


// 测试方法
const refInput = ref(null)
onMounted(() => {
  console.log('refinput', refInput)
  // refInput.value.$refs.refInput.select()
  refInput.value.refInput.select()
})
复制代码


父组件里面的用法是一样的,只是需要再套一层,才能拿到自定义组件内部的UI库组件。


image.png


看看结构:


太长了,还在下面。


image.png


这个就比较近了。


话说为啥弄得这么多属性和方法事件呀?


父组件调用子组件内部的方法


上面那种方式,还可以让父组件调用子组件内部定义的方法,比如内部定义一个


const setInput = () => {
      value.value = new Date()
    }
复制代码


父组件可以这样调用


refInput.value.setInput()
复制代码


总结



其实事件和方法,并没有封装,而是直接就可以使用的。 这是 element-plus 测试的结果,其他UI库没有测试。


插槽需要写一个 v-for 就可以实现传递,而且是通用的代码。 属性 就需要规划一下了,看设计要求,哪些放在 props里面,哪些放在attrs 里面。



相关文章
|
22天前
|
缓存 JavaScript UED
Vue3中v-model在处理自定义组件双向数据绑定时有哪些注意事项?
在使用`v-model`处理自定义组件双向数据绑定时,要仔细考虑各种因素,确保数据的准确传递和更新,同时提供良好的用户体验和代码可维护性。通过合理的设计和注意事项的遵循,能够更好地发挥`v-model`的优势,实现高效的双向数据绑定效果。
126 64
|
22天前
|
前端开发 JavaScript 测试技术
Vue3中v-model在处理自定义组件双向数据绑定时,如何避免循环引用?
Web 组件化是一种有效的开发方法,可以提高项目的质量、效率和可维护性。在实际项目中,要结合项目的具体情况,合理应用 Web 组件化的理念和技术,实现项目的成功实施和交付。通过不断地探索和实践,将 Web 组件化的优势充分发挥出来,为前端开发领域的发展做出贡献。
28 8
|
21天前
|
存储 JavaScript 数据管理
除了provide/inject,Vue3中还有哪些方式可以避免v-model的循环引用?
需要注意的是,在实际开发中,应根据具体的项目需求和组件结构来选择合适的方式来避免`v-model`的循环引用。同时,要综合考虑代码的可读性、可维护性和性能等因素,以确保系统的稳定和高效运行。
21 1
|
21天前
|
JavaScript
Vue3中使用provide/inject来避免v-model的循环引用
`provide`和`inject`是 Vue 3 中非常有用的特性,在处理一些复杂的组件间通信问题时,可以提供一种灵活的解决方案。通过合理使用它们,可以帮助我们更好地避免`v-model`的循环引用问题,提高代码的质量和可维护性。
32 1
|
25天前
|
JavaScript API 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
27天前
|
JavaScript 前端开发 开发者
vue 数据驱动视图
总之,Vue 数据驱动视图是一种先进的理念和技术,它为前端开发带来了巨大的便利和优势。通过理解和应用这一特性,开发者能够构建出更加动态、高效、用户体验良好的前端应用。在不断发展的前端领域中,数据驱动视图将继续发挥重要作用,推动着应用界面的不断创新和进化。
|
1天前
|
JavaScript 关系型数据库 MySQL
基于VUE的校园二手交易平台系统设计与实现毕业设计论文模板
基于Vue的校园二手交易平台是一款专为校园用户设计的在线交易系统,提供简洁高效、安全可靠的二手商品买卖环境。平台利用Vue框架的响应式数据绑定和组件化特性,实现用户友好的界面,方便商品浏览、发布与管理。该系统采用Node.js、MySQL及B/S架构,确保稳定性和多功能模块设计,涵盖管理员和用户功能模块,促进物品循环使用,降低开销,提升环保意识,助力绿色校园文化建设。
|
29天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
32 1
vue学习第一章
|
29天前
|
JavaScript 前端开发 索引
vue学习第三章
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中的v-bind指令,包括基本使用、动态绑定class及style等,希望能为你的前端学习之路提供帮助。持续关注,更多精彩内容即将呈现!🎉🎉🎉
26 1
vue学习第三章
|
29天前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
35 1
vue学习第四章
下一篇
DataWorks