【Vue3】自定义组件directiveapp.use()

历史小剧场

崇祯很勤政,崇祯并非王国之君,弘光很昏庸,弘光活该倒霉,几百年来,我们都这样认为。
但我们之所以一直这样认为,只是因为有人这样告诉我们。
之所以有人这样告诉我们,是因为他们希望我们这样认为。 ---- 《明朝那些事儿》

app.directive

作用:注册自定义指令

自定义指令

指令钩子函数
  • created: 在绑定元素的attribute前或事件监听器前调用;
  • beforeMount: 在元素插入到DOM前调用;
  • mounted: 在绑定元素的父组件及它自己的所有子节点都挂载完成后调用(常用)
  • beforeUpdate: 绑定元素的父组件更新前调用
  • updated: 在绑定元素的父组件及它自己的所有子节点都更新后调用(常用)
  • beforeUnmount: 绑定元素的父组件卸载前调用
  • unmounted: 绑定元素的父组件卸载后调用
钩子参数

案例

export default {
    mounted(el: any, binding: any, vnode: any, prevNode: any) {
        console.log("tab mounted", el, binding, vnode, prevNode)
        const { activeClass, curIndex } = binding.value;
        const buttonList = el.querySelectorAll("button");
        buttonList[curIndex].classList.add(activeClass);
    },
    updated(el: any, binding: any, vnode: any, prevNode: any) {
        console.log("tab updated", el, binding, vnode, prevNode)
        const buttonList = el.querySelectorAll("button");
        let { activeClass, curIndex } = binding.oldValue;
        buttonList[curIndex].classList.remove(activeClass);
        activeClass = binding.value.activeClass;
        curIndex = binding.value.curIndex;
        buttonList[curIndex].classList.add(activeClass);
    }
}
  1. el: 指定绑定到的元素。
    在这里插入图片描述
  2. binding: 对象,通常包含如下属性
    1. value: 传递给指令的值
    2. oldValue: 之前的值,仅在 beforeUpdate 和 updated 中可用
    3. arg: 传递给指令的参数
    4. modifers: 一个包含修饰符的对象
    5. instance: 使用该指令的组件实例
    6. dir: 指令的定义对象
      在这里插入图片描述
  3. vnode: 代表绑定元素的底层VNode
    在这里插入图片描述
  4. prevNode: 代表之前的渲染中指定所绑定元素的VNode。仅在 beforeUpdate 和 updated 钩子中可用
    在这里插入图片描述
使用

这里,我们封装一个自定义v-tab指令来处理按钮点击切换样式变幻问题

定义一个组件 TestDirective.vue

<!-- TestDirective.vue -->
<template>
    <div>
        <div class="tab" 
        @click="handleClick($event)"
        v-tab="{  
            activeClass: 'active',
            curIndex
        }">
            <button data-index="0">按钮一</button>
            <button data-index="1">按钮二</button>
            <button data-index="2">按钮三</button>
        </div>
    </div>
</template>

<script lang="ts">
import { ref } from 'vue'
import { tab } from '../directives'

export default {
    name: 'TestDirective',
    directives: {
        tab
    },
    setup() {
        const curIndex = ref<number>(0)
        const handleClick = (event: MouseEvent) => {
            const tar = event.target as HTMLElement
            const className = tar.className

            if (Object.is(className, '')) {
                const index = parseInt(tar.dataset?.index ?? "")
                curIndex.value = index
            }
        }

        return {
            handleClick,
            curIndex
        }
    }
}
</script>

<style lang="scss" scoped>
.tab {
    .active {
         background-color: skyblue;
         border: 2px solid slategrey;
         color: white;
    }
}
</style>

在src下面创建directives文件夹来存放自定义指令

在这里插入图片描述
index.ts

import tab from './tab'

export {
    tab
}

tab.ts

export default {
    mounted(el: any, binding: any, vnode: any, prevNode: any) {
        console.log("tab mounted", el, binding, vnode, prevNode)
        const { activeClass, curIndex } = binding.value;
        const buttonList = el.querySelectorAll("button");
        buttonList[curIndex].classList.add(activeClass);
    },
    updated(el: any, binding: any, vnode: any, prevNode: any) {
        console.log("tab updated", el, binding, vnode, prevNode)
        const buttonList = el.querySelectorAll("button");
        let { activeClass, curIndex } = binding.oldValue;
        buttonList[curIndex].classList.remove(activeClass);
        activeClass = binding.value.activeClass;
        curIndex = binding.value.curIndex;
        buttonList[curIndex].classList.add(activeClass);
    }
}

运行之后,我们可以鼠标点击按钮切换样式
在这里插入图片描述

app.use

安装插件。 必须带一个install()方法

封装插件

这里,我们自己封装一个MyUI插件,且在插件里有两个自定义组件:MyButton 和 MyInput

在这里插入图片描述
MyButton.vue

<!-- MyButton.vue -->
<template>
    <div>
        <button class="my-button"><slot></slot></button>
    </div>
</template>

<script lang="ts">
export default {
    name: 'MyButton',
}
</script>

<style lang="scss" scoped>
    .my-button {
        background-color: #41b883;
        color: #fff;
        border: none;
        border-radius: 10px;
        width: 80px;
    }
</style>

MyInput.vue

<!--  -->
<template>
    <div>
        <input class="my-input" type="text" placeholder="placeholderText" />
    </div>
</template>

<script lang="ts">
export default {
    name: 'MyInput',
    props: {
        placeholderText: {
            type: String,
            default: 'This is my input'
        }
    }
}
</script>

<style lang="scss" scoped>
    .my-input {
        width: 180px;
        border: 1px solid #ccc;
        border-radius: 4px;
        padding: 4px;
    }
</style>

index.ts

import MyButton from './MyButton.vue'
import MyInput from './MyInput.vue'

const componentsPool: Map<String, any> = new Map()
componentsPool.set(MyButton?.name ?? "", MyButton)
componentsPool.set(MyInput?.name ?? "", MyInput)

export default {

    install(app: any, options: any) {
        console.log("options => ", options)
        console.log("componentsPool => ", componentsPool)
        if (options?.components.length > 0) {
            // 按需加载
            options.components.map((com: String) => {
                componentsPool.has(com) && app.component(com, componentsPool.get(com))
            })
        } else {
            // 全部加载
            for (let [name, com] of componentsPool.entries()) {
                app.component(name, com)
            }
        }
    }
}

注意:在插件加载逻辑中,我们实现了按需加载。就是,如果我们在app.use()方法的第二个参数中传入components数组且长度大于0就进行按需加载,优化性能,否则的话,全部加载。

注册

我们在程序入口文件main.ts中进行注册

import MyUI from './libs/MyUI'
app.use(MyUI, {
    components: ['MyButton', 'MyInput']
})
使用

然后,我们创建一个TestUse.vue

<!--  -->
<template>
    <div>
        <my-button>测试按钮</my-button>
        <my-input></my-input>
    </div>
</template>

<script lang="ts">
export default {
    name: "TestUse",
}
</script>

<style lang="scss" scoped>

</style>

按照上面我们运行结果则是两个都可以展示
在这里插入图片描述
如果,我们在注册的时候只加载按钮

app.use(MyUI, {
    components: ['MyButton']
})

则只展示按钮
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/668355.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java | Leetcode Java题解之第121题买卖股票的最佳时机

题目&#xff1a; 题解&#xff1a; public class Solution {public int maxProfit(int prices[]) {int minprice Integer.MAX_VALUE;int maxprofit 0;for (int i 0; i < prices.length; i) {if (prices[i] < minprice) {minprice prices[i];} else if (prices[i] -…

PieCloudDB Database Flink Connector:让数据流动起来

面对客户环境中长期运行的各种类型的传统数据库&#xff0c;如何优雅地设计数据迁移的方案&#xff0c;既能灵活地应对各种数据导入场景和多源异构数据库&#xff0c;又能满足客户对数据导入结果的准确性、一致性、实时性的要求&#xff0c;让客户平滑地迁移到 PieCloudDB 数据…

快递100使用

1.快递100 接口文档 链接: 接口文档 2.授权参数 授权Key: qZgsNFSo5391 customer&#xff1a;8EEA8C4FB90B275E228CA322EF0E61E5 3.技术文档 链接: 技术文档 4.使用 <dependency><groupId>com.github.kuaidi100-api</groupId><artifactId>sdk&l…

AI大模型探索之路-实战篇12: 构建互动式Agent智能数据分析平台:实现多轮对话控制

系列篇章&#x1f4a5; AI大模型探索之路-实战篇4&#xff1a;深入DB-GPT数据应用开发框架调研 AI大模型探索之路-实战篇5&#xff1a;探索Open Interpreter开放代码解释器调研 AI大模型探索之路-实战篇6&#xff1a;掌握Function Calling的详细流程 AI大模型探索之路-实战篇7…

【CPP】双端队列简介(deque)

简介&#xff1a;双端队列(deque) 目录 1.概述2.特点3.底层原理 1.概述 双端队列&#xff1a;是一种顺序表和顺序表的结合数据结构&#xff0c;不是队列。 它提供顺序表的[]下标访问和链表的中间头部的较高效率插入删除操作。 2.特点 顺序表的优缺点&#xff1a; 优点&…

网络安全基础技术扫盲篇 — 名词解释之“数据包“

用通俗易懂的话说&#xff1a; 数据包就像是一个信封。当你写信给某个人时&#xff0c;你将内容写在一张纸上&#xff0c;然后将纸叠起来并放入信封中&#xff0c;就形成了一个完整要发送的数据内容。信封上有发件人和收件人的详细地址&#xff0c;还有一些其他必要的信息&…

动态规划(Dynamic-Programming)问题讲解

动态规划类问题 从已知子问题的解&#xff0c;推导出当前问题的解 推导过程可以表达为一个数学公式用一维或二维数组来保存之前的计算结果&#xff08;可以进一步降维优化&#xff09; 将当前问题 分解成子问题 &#xff0c;找出递归公式&#xff0c;分阶段进行求解 求解过程中…

【scau大数据技术与原理2】综合性实验Spark集群的安装和使用——安装启动spark shell篇

实验内容简介&#xff1a; Spark是一个分布式计算框架&#xff0c;常用于大数据处理。本次实验中&#xff0c;首先设计一个包含主节点和从节点的Spark集群架构&#xff0c;并在CentOS的Linux环境下进行搭建。通过下载并解压Spark安装包&#xff0c;配置环境变量和集群参数&…

python分别保存聚类分析结果+KeyError: ‘CustomerID‘报错

如何在完成聚类分析后按聚类编号保存数据并且带上原数据所属ID # 将每个聚类的数据保存到不同的文件中 for cluster_id in range(6): # 假设共有6个聚类cluster_data data[data[cluster] cluster_id]cluster_data_with_customer_id cluster_data.copy()cluster_data_with_…

量化研究---强大的可转债分析系统上线,提供api,实时数据支持

今天把可转债实盘的分析模型拿出来&#xff0c;放在服务器方便选股分析&#xff0c;方便后面对接大qmt直接选股交易 强大的禄得可转债自定义因子轮动系统完成&#xff0c;可转债三低为例子 自定义因子实盘的框架 自定义因子轮动框架非常强大 网页 http://120.78.132.143:8023/…

MongoDB~俩大特点管道聚合和数据压缩(snappy)

场景 在MySQL中&#xff0c;通常会涉及多个表的一些操作&#xff0c;MongoDB也类似&#xff0c;有时需要将多个文档甚至是多个集合汇总到一起计算分析&#xff08;比如求和、取最大值&#xff09;并返回计算后的结果&#xff0c;这个过程被称为 聚合操作 。 根据官方文档介绍&…

day1、2-数1

数学一主要考查高数、线性代数、概率统计这三个方面&#xff0c;其中高数占比56%、线性代数占比22%、概率统计占比22% 题做完 要产生1套理论 24年真题 1. 选C sinx的话不影响奇偶 奇偶函数的积分 0到a的积分为一个常数 求导的话 奇函数导出来一定是偶函数&#xff0c;偶函…

【机器学习系列】掌握随机森林:从基础原理到参数优化的全面指南

目录 目录 一、随机森林简介 (一)随机森林模型的基本原理如下&#xff1a; (二)随机森林模型的优点包括&#xff1a; (三)森林中的树的生成规则如下&#xff1a; (四)在随机森林中&#xff0c;每棵树都使用不同的训练集进行训练&#xff0c;原因如下 随机森林的分类性能&…

day-36 删除链表的倒数第 N 个结点

思路 首先计算出链表的长度&#xff0c;然后删除第n个节点即可&#xff0c;但要注意考虑特殊情况 解题方法 特殊情况&#xff1a;1.删除节点为最后一个节点 2.删除节点为头结点 Code /*** Definition for singly-linked list.* public class ListNode {* int val;* …

函数:计算数组的元素和

一、计算数组的元素和 参数传递给函数时&#xff0c;实际上只有数组的首地址作为指针传递给了函数。 在函数定义中的int a[ ]等价于int *a。在只有地址信息的情况下&#xff0c;是无法知道数组里有多少个元素的&#xff0c;因此在计算数组中的元素和时&#xff0c;要加一个参…

MongoDB下载安装入门 + SpringBoot简单集成

MongoDB安装入门 SpringBoot简单集成 MongoDB下载安装下载安装连接图形化界面MongoDB Compass Navicat Premium Spring Boot集成API操作添加maven配置数据库连接调用Mongo API MongoDB下载安装 下载安装 MongoDB官网地址&#xff1a;https://www.mongodb.com/ 下载地址&…

CobaltStrike基本渗透

目录 CobaltStrike简介 主要功能&#xff1a; 使用注意&#xff1a; 在使用CobaltStrike进行渗透测试时&#xff0c;务必遵守法律法规&#xff0c;并获得合法授权。 CobaltStrike安装 前提 安装 服务端安装 windows安装 CS基本使用 监听器配置 一些基本的攻击…

UnityAPI学习之游戏物体的方法使用

目录 游戏物体 创建游戏物体的三种方式 组建的获取和查找 游戏物体的方法与其他成员变量 游戏物体的生成 游戏物体的激活状态/标签(tag)/层级(layer) 游戏物体的激活与失活 游戏物体的查找 1. 名称查找(Find) 2. 通过标签查找游戏物体&#xff08;FindGameObjectWithT…

Leecode---动态规划---打家劫舍 / 乘积最大子数组

动态规划法&#xff1a; 思路&#xff1a; &#xff08;1&#xff09;状态定义&#xff1a;dp[i]代表前i家能偷盗的最大金额 &#xff08;2&#xff09;状态初始化&#xff1a;如果只有一家&#xff0c;只能偷这家dp[0]nums[0]&#xff1b;如果有两家&#xff0c;因为是连通的&…

fluent UI v9版本Dialog右上角x按钮聚焦问题解决

右上角x按钮聚焦效果展示 第一次点击不会聚焦&#xff0c;第二次或多次点击会出现这种情况。如果多个地方公用一个页面里&#xff0c;这个页面包含这个组件&#xff0c;那其它页面刚打开弹框就是聚焦状态&#xff0c;是个样式的问题。 解决&#xff1a; import * as React fr…