首页 > 其他分享 >Vue3 组件封装的一些技巧和心得 转载

Vue3 组件封装的一些技巧和心得 转载

时间:2024-09-04 15:15:26浏览次数:11  
标签:封装 default 插槽 value Vue3 组件

在日常开发的过程中,使用Vue的组件进行业务拆分,代码解耦是一个很好的选择;

今天就来分享一下我在使用Vue3进行组件封装的一些技巧和心得,希望能够帮助到大家;

1. 组件特性

Vue中组件是一个独立的实例,每个组件都有共通点,就是:属性插槽事件方法

在日常我们使用第三方组件库的时候,组件库的文档都会说明上面四个特性,而组件封装就是围绕这四个特性进行的;

2. 组件封装

2.1 组件继承

很多情况下,我们会在一个组件的基础上进行扩展,这个时候就需要用到组件继承;

Vue2的时候,我们可以使用extends关键字进行组件继承,但是在Vue3中,extends关键字已经被废弃了;

Vue3中,如果想要实现组件继承其实很简单,要明白一个组件其实就是一个js对象,我们可以直接将一个组件对象合并,然后注册成一个新的组件;

import { createApp } from "vue";
import App from "./App.vue";
import ElementPlus, { ElInput } from "element-plus";
import "element-plus/dist/index.css";
import { merge } from "lodash";

const app = createApp(App);
app.use(ElementPlus);

// 组件继承,将ElInput组件的placeholder属性默认值改为"请输入"
app.component(
  "ElInput",
  merge(ElInput, {
    props: {
      placeholder: {
        default: "请输入"
      }
    }
  })
);

app.mount("#app");

这里直接使用了lodashmerge方法,将ElInput组件的props属性进行了合并,然后覆盖注册成了一个新的组件;

因为有很多小伙伴遇到一个问题就是需要固定ElTable组件的一些属性,比如borderstripesize等,这个时候用这种方法就非常方便;

2.2 组件插槽

上面的组件继承只是简单的改变了组件的默认属性,但是如果我们想要改变组件的结构,就需要用到组件插槽;

通常情况下我们要拆分组件的业务,然后封装成业务组件,这个时候可能会使用到多个组件;

这个时候组件里面有很多组件,需要替换组件里面的组件里面的插槽,这个时候就需要透传插槽;

<!--  透传插槽  -->
<template>
<div>
区域A这里有一个组件,这个组件需要替换插槽
<el-tree :data="treeData">
<template v-if="$slots.tree" #default="{ node, data }">
<slot name="tree" :node="node" :data="data" />
</template>
</el-tree>
</div>

<div>
区域B这里有一个组件,这个组件需要替换插槽
<el-table :data="tableData">
<template v-if="$slots.default">
<slot />
</template>
</el-table>
</div>
</template>

<script>
export default {
data() {
return {
treeData: new Array(10)
.fill(0)
.map((_, index) => ({ label: "label" + index })),
tableData: [],
};
},
};
</script>

通过使用$slots可以获取到组件的插槽,然后通过v-if判断是否有插槽,如果有插槽就进行透传;

除了这种方式之外,还可以使用jsx语法,这种方式更加灵活;


<script lang="jsx">
export default {
render() {
const areaA = (
<div>
区域A这里有一个组件,这个组件需要替换插槽
<el-tree data={treeData}>
{{
default: this.$slots.tree
}}
</el-tree>
</div>
);

const areaB = (
<div>
区域B这里有一个组件,这个组件需要替换插槽
<el-table data={tableData}>
{{
default: this.$slots.default
}}
</el-table>
</div>
);

return (
<div>
{areaA}
{areaB}
</div>
);
}
}
</script>

setup语法中是没有this的,这个使用需要获取$slots的时候需要使用useSlots方法;

2.3 组件事件和透传 attrs

Vue2中,我们可以使用$listeners来获取组件的事件,然后进行透传;

而在Vue3中,$listeners已经被废弃了,$listeners$attrs都被合并到了$attrs中;

<!-- 组件 -->
<template>
<div v-bind="$attrs"></div>
</template>

<!-- 父组件 -->
<template>
<div>
<MyComponent
class="my-class"
@click="handleClick"
/>
</div>
</template>

Vue3中,我们可以直接使用$attrs来获取组件的事件,然后进行透传;

例如上面的例子,我们可以直接在组件中使用$attrs来获取到class@click事件,等同于下面的写法;

<!-- 组件 -->
<template>
<div class="my-class" @click="handleClick"></div>
</template>

但是这里其实有一个小技巧,就是Vue3默认属性是可以透传的,例如上面的例子其实可以简化成下面的写法;

<!-- 组件 -->
<template>
<div></div>
</template>

<!-- 父组件 -->
<template>
<div>
<MyComponent
class="my-class"
@click="handleClick"
/>
</div>
</template>

就是组件里面什么都不写,最后在父组件中使用这个组件的时候,属性会透传到组件中的根元素上;

参考:透传 Attributes[1]

了解这个特性就可以这样封装组件:

<!-- 组件 -->
<template>
<el-dialog>
</el-dialog>
</template>

<!-- 父组件 -->
<template>
<div>
<MyComponent
v-model="visible"
width="500px"
/>
</div>
</template>

通常我们会封装一个Dialog组件来解耦业务,这个时候直接将Dialog作为根元素,然后可以将v-modelwidth属性透传到Dialog组件上;

这样不需要写Dialog组件开启关闭的双向绑定的代码,前提是不需要在组件内部操作Dialog的开启关闭;

2.4 组件方法

Vue2中,我们可以通过this.$refs.xxx来获取到组件的实例,然后调用组件的方法;

Vue3中,我们可以通过ref来获取到组件的实例,然后调用组件的方法;

但是不管是Vue2还是Vue3,在组件内部想要使用组件的子组件的方法都不是一件容易的事情;

通常都是手动将组件的实例获取到,然后再重新定义在组件的methods中;

<!-- 组件 -->
<template>
<div>
<el-input ref="input" />
</div>
</template>

<script>
export default {
methods: {
focus() {
this.$refs.input.focus();
},
},
};
</script>

组件的方法通常没有啥特别好的方式,除了我上面的这种方式之外,还有小伙伴是直接将ref返回出去:

<template>
<div>
<el-input ref="input" />
</div>
</template>

<script>
export default {
methods: {
inputRef() {
return this.$refs.input
},
},
};
</script>

当然还有一种偷懒的方式:

<template>
<div>
<el-input ref="input" />
</div>
</template>

<script>
export default {
mounted() {
Object.values(this.$refs.input).forEach((value) => {
if (typeof value === 'function') {
this[value.name] = (...args) => value(...args);
}
});
},
methods: {
inputRef() {
return this.$refs.input
},
},
};
</script>

不过这种偷懒的方式只能在options api中使用,因为在composition api中是没有this的;

对于setup语法,如果需要使用组件的方法,可以使用getCurrentInstance来获取到组件的实例,然后将方法挂载到exposed上;

<template>
<div>
<el-input ref="input" />
</div>
</template>

<script setup>
import { getCurrentInstance, onMounted, ref } from "vue";

const instance = getCurrentInstance();
const input = ref(null);
onMounted(() => {
Object.values(input.value).forEach((value) => {
if (typeof value === "function") {
instance.exposed[value.name] = (...args) => value(...args);
}
});
});
</script>

这种方式不太稳定,因为exposedVue3的一个私有属性,不建议使用;

setup语法中如果需要暴露组件的内部方法,需要使用defineExpose来暴露;

<script setup>
// ... 省略其他代码

defineExpose({
focus: () => {
input.value.focus();
},
});
</script>

总结

这次带来的是Vue3的组件封装的一些技巧,主要是setup语法的一些特性,以及Vue3中的一些奇淫技巧;

Vue3的组件封装相比Vue2来说更加的灵活,但是也更加的复杂,需要我们在使用的时候多加注意;

这次分享的只是一些技术上的点,组件封装是一门非常大的学问,需要我们在实际的项目中多加实践;

作者:田八

链接:https://juejin.cn/post/7247050634191454266

标签:封装,default,插槽,value,Vue3,组件
From: https://www.cnblogs.com/testzcy/p/18396578

相关文章

  • Vue3 动态子页面和菜单栏同步
    动态子页面<router-view></router-view>显示子页面的内容main.vue<template><a-layoutid="components-layout-demo-top-side"><the-header-view></the-header-view><a-layoutstyle="padding:24px0;background......
  • React18+TypeScript4+Vue3:‌入门到实战,‌灵活技术选型指南
    React18+TypeScript4+Vue3:‌入门到实战,‌灵活技术选型指南在当今的前端开发领域,‌React、‌TypeScript和Vue是三大热门技术,‌它们各自拥有独特的优势和广泛的应用场景。‌掌握这些技术,‌不仅能够提升你的开发效率,‌还能帮助你在不同项目中做出更加合适的技术选型。‌本文将带......
  • vue3 地图(天地图,百度地图,腾讯地图,高德地图)封装组件调用 带地图搜索功能common_tencent
    废话不多说直接上组件代码:<template><!--地图--><divclass="containerw"><divid="map"class="mapradius-md":style="{width:width,height:height}"></div></div><......
  • 牛逼!Vue3.5的useTemplateRef让ref操作DOM更加丝滑
    前言vue3中想要访问DOM和子组件可以使用ref进行模版引用,但是这个ref有一些让人迷惑的地方。比如定义的ref变量到底是一个响应式数据还是DOM元素?还有template中ref属性的值明明是一个字符串,比如ref="inputEl",怎么就和script中同名的inputEl变量绑到一块了呢?所以Vue3.5推出了一个us......
  • Vue3打造前台+中台通用开发提效解决方案-42种前台业务模型
    Vue3打造前台+中台通用开发提效解决方案:‌42种前台业务模型引言随着前端技术的飞速发展,‌Vue.js作为主流前端框架之一,‌凭借其易用性和高性能,‌在开发领域占据了一席之地。‌特别是Vue3的发布,‌带来了CompositionAPI、‌Teleport等新特性,‌进一步提升了开发效率和用户体验。‌......
  • Electron32-ViteOS桌面版os系统|vue3+electron+arco客户端OS管理模板
    基于electron32+vue3setup+pinia2桌面端os管理解决方案ElectronVue3OS。vue3-electron32-os全新原创Electron32+Vite5+Vue3+Pinia2+ArcoDesign+Echarts+Swiper搭建桌面版os管理模板。内置macos+windows两种桌面布局风格、自研可拖拽式栅格布局模板引擎、支持JSON动态配置桌面菜......
  • 前端Pinia教程,Pinia+Vue3+Vite+TypeScript+腾讯IM聊天解决方案项目实战
    前端Pinia教程:‌Pinia+Vue3+Vite+TypeScript+腾讯IM聊天解决方案项目实战在前端开发中,‌随着Vue3的普及和Vite构建工具的兴起,‌结合TypeScript和Pinia进行状态管理成为了一个高效且受欢迎的选择。‌本文将详细介绍如何结合这些技术栈以及腾讯IM聊天解决方案,‌搭建一个高效的前端......
  • 前端项目实战Uniapp移动端项目+Vue3+Typescript+AntdVue管理平台
    ‌前端项目实战:‌构建Uniapp移动端项目与Vue3+Typescript+AntdVue管理平台‌在当今的前端开发领域,‌技术的不断迭代和创新为开发者带来了更多的选择和可能性。‌本文将介绍如何使用Uniapp框架开发移动端项目,‌并结合Vue3、‌Typescript以及AntdVue来构建一个高效的管理平台。......
  • 65V高压高效宽频双向同步升降压恒压恒流控制制QFN32L小体积封装
    PC1065是一款同步升降压控制器,适用于驱动高效电源转换器中的MOSFET或氮化镓(GaN)等功率器件。它支持高达65V的宽输入和输出电压范围,并可在降压、升降压和升压模式之间无缝转换。PC1065集成了具有UVLO保护功能的上管和下管栅极驱动器。它提供可编程电感峰值电流限制和输出平......
  • VUE - 动态渲染组件
    VUE-动态渲染组件 环境:vue21. 创建组件 创建文件:wbsgrap.vue<template><divclass="cbox">模型构件cc</div></template><script>exportdefault{data(){return{};},mounted(){},methods:{},};</script>......