当前位置: 首页 > news >正文

二次封装的方法

二次封装

我们开发中经常需要封装一些第三方组件,那么父组件应该怎么传值,怎么调用封装好的组件原有的属性、插槽、方法,一个个调用虽然可行,但十分麻烦,我们一起来看更简便的方法。

二次封装组件,属性怎么传

attrs 主要接收不在 props 里定义,但父组件又传过来的属性,通过 v-bind=“$attrs”,可以将属性全部传给封装起来的组件(如下面例子中的 el-input ),而不需要一个一个传

// 父组件
<template><div><MyInput v-model="text" placeholder="请输入地址"></MyInput></div>
</template><script setup>
import MyInput from './components/MyInput.vue';
import { ref } from 'vue';
const text = ref('123');
</script>
// MyInput 组件
<template><div class="item"><el-input v-bind="$attrs"></el-input></div>
</template>
<script setup>
import { onMounted, useAttrs } from 'vue';
const props = defineProps({// placeholder:{//   type:String// }// attrs包含的是不在props中的属性// 如果这里有placeholder,下面输出attrs就不会有这个placeholder
});
const attrs = useAttrs(); // 需要引入 vue 中的 useAttrs ,调用 useAttrs 获取 attrs
onMounted(() => {console.log(attrs); // 输出如下图
})
</script>

在这里插入图片描述

监听事件怎么实现

$listeners :包含了父作用域中(不含 .native 修饰器的)v-on 事件监听器,他可以通过 v-on=“listeners” 传入内部组件,监听内部组件的所有事件.

<template><div><MyInputv-model="text"placeholder="请输入地址"ref="focusRef"@input="inputNum"><template #prepend="{}"><el-select v-model="select" placeholder="Select" style="width: 115px"><el-option label="A" value="1" /><el-option label="B" value="2" /><el-option label="C" value="3" /></el-select></template><template #append><el-button :icon="Search" /></template></MyInput></div>
</template>
<script setup>
import MyInput from "./components/MyInput.vue";
import { onMounted, ref } from "vue";
import { Search } from "@element-plus/icons-vue";
const text = ref("123");
const select = ref("");
const focusRef = ref();
onMounted(() => {focusRef.value.focus();
});
const inputNum = (val) => { // 被监听事件触发时调用的方法console.log("输出:" + val);
};
</script>// 子组件
<template><div class="item"><el-input v-bind="$attrs" v-on="$listeners" ref="inp"><template v-for="(value, name) in $slots" #[name]="slotData"><slot :name="name" v-bind="slotData || {}"></slot></template></el-input></div>
</template>
<script setup>
import { onMounted, useSlots, useAttrs, nextTick, ref } from "vue";const attrs = useAttrs();
const slots = useSlots();
const inp = ref();
onMounted(() => {console.log(attrs);console.log(slots);console.log(inp.value);
});
defineExpose(new Proxy({},{// 使用 Proxy 代理暴露出去get(_target, prop) {return inp.value?.[prop];},has(_target, prop) {return prop in inp.value;},})
);
</script>

插槽怎么使用

二次封装组件时经常需要往原组件的插槽中传递内容,这时要让原始组件知道我们使用了哪些插槽,可以使用 $slots

$slots 是一个表示父组件所传入[插槽]的对象,我们可以在子组件中通过 $slots 获取到父组件传过来所有插槽名,接下来子组件遍历 $slots 动态渲染插槽即可

// 父组件
<template><div><MyInput v-model="text" placeholder="请输入地址"><template #prepend="{}"><el-select v-model="select" placeholder="Select" style="width: 115px"><el-option label="A" value="1" /><el-option label="B" value="2" /><el-option label="C" value="3" /></el-select></template><template #append><el-button :icon="Search" /></template></MyInput></div>
</template>
<script setup>
import MyInput from './components/MyInput.vue';
import { ref } from 'vue';
import { Search } from '@element-plus/icons-vue'
const text = ref('123');
const select = ref('')
</script>
// 也可以往插槽传值 slotData
<template><div class="item"><el-input v-bind="$attrs"><template v-for="(value,name) in $slots" #[name]="slotData"><slot :name="name" v-bind="slotData || {}"></slot></template></el-input></div>
</template>
<script setup>
import { onMounted, useSlots, useAttrs } from 'vue';const attrs = useAttrs();
const slots = useSlots() // 引入 useSlots
onMounted(() => {console.log(attrs);console.log(slots); // 输出如下图
})
</script>

在这里插入图片描述

父组件的 ref 怎么调用目标组件内部方法

我们要想通过父组件的 ref 调用到子组件内部方法(如 el-input 的 focus 方法)可以怎么做?其实可以通过 ref 链式调用,比如 focusRef.value.inp.value.focus(),但代码的可读性差

更好的方法是将所有方法暴露出去供父组件调用,可以利用 Proxy 对象来创建一个代理,并通过 defineExpose 将这个代理暴露给父组件。这个代理的目的是拦截对特定属性的访问,并将这些访问重定向到 inp.value(即 el-input 的引用)上,这样,父组件就可以通过组件的 ref 访问到 el-input 实例的属性

// 父组件
<template><div><MyInput v-model="text" placeholder="请输入地址" ref="focusRef"><template #prepend="{}"><el-select v-model="select" placeholder="Select" style="width: 115px"><el-option label="A" value="1" /><el-option label="B" value="2" /><el-option label="C" value="3" /></el-select></template><template #append><el-button :icon="Search" /></template></MyInput></div>
</template>
<script setup>
import MyInput from "./components/MyInput.vue";
import { onMounted, ref } from "vue";
import { Search } from "@element-plus/icons-vue";
const text = ref("123");
const select = ref("");
const focusRef = ref();
onMounted(() => {focusRef.value.focus();
});
</script>
// 子组件
<template><div class="item"><el-input v-bind="$attrs" ref="inp"><template v-for="(value, name) in $slots" #[name]="slotData"><slot :name="name" v-bind="slotData || {}"></slot></template></el-input></div>
</template>
<script setup>
import { onMounted, useSlots, useAttrs, nextTick, ref } from "vue";const attrs = useAttrs();
const slots = useSlots();
const inp = ref();
onMounted(() => {console.log(attrs);console.log(slots);console.log(inp.value); // 这里输出如下图
});
defineExpose( // 使用 Proxy 代理暴露出去new Proxy({},{get(_target, prop) {return inp.value?.[prop];},has(_target, prop) {return prop in inp.value;},})
);
</script>

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

整体效果如图

在这里插入图片描述

http://www.lryc.cn/news/528031.html

相关文章:

  • 消息队列篇--通信协议篇--网络通信模型(OSI7层参考模型,TCP/IP分层模型)
  • Python实现U盘数据自动拷贝
  • 汇编的使用总结
  • DeepSeek理解概率的能力
  • AI 浪潮席卷中国年,开启科技新春新纪元
  • AI时代的网络安全:传统技术的落寞与新机遇
  • 可以称之为“yyds”的物联网开源框架有哪几个?
  • 线程局部存储tls的原理和使用
  • RK3588平台开发系列讲解(ARM篇)ARM64底层中断处理
  • CAN总线
  • qwen2.5-vl:阿里开源超强多模态大模型(包含使用方法、微调方法介绍)
  • python实现dbscan
  • 学习数据结构(3)顺序表
  • 正在更新丨豆瓣电影详细数据的采集与可视化分析(scrapy+mysql+matplotlib+flask)
  • wx043基于springboot+vue+uniapp的智慧物流小程序
  • 每日一题 430. 扁平化多级双向链表
  • UE学习日志#14 GAS--ASC源码简要分析10 GC相关
  • 使用Python和Qt6创建GUI应用程序--关于Qt的一点介绍
  • C#@符号在string.Format方法中作用
  • Next.js 14 TS 中使用jwt 和 App Router 进行管理
  • 【贪心算法】洛谷P1090 合并果子 / [USACO06NOV] Fence Repair G
  • Windows11无法打开Windows安全中心主界面
  • 下载arm架构的deb包的方法
  • 【Day29 LeetCode】动态规划DP
  • 5分钟带你获取deepseek api并搭建简易问答应用
  • LeetCode题练习与总结:最短无序连续子数组--581
  • 探秘 TCP TLP:从背景到实现
  • linux学习之网络编程
  • scrol家族 offset家族 client家族学习
  • css-background-color(transparent)