vue2-抽象组件-nexter

前言

在一些表单中,为了优化用户体验,通常需要在用户按下enter键之后跳到下一个input框或者button中。

对于js,可以选择获取表单中的所有input 和button后逐个添加键盘enter事件,现在,我们将这个逻辑封装为一个抽象组件,使得下面的代码能够实现这个效果:

<sss-nexter>
    <el-input></el-input>
    <el-input></el-input>
    <sss-button type="main" round>click me</sss-button>
</sss-nexter>

20230418_191419

您的浏览器不支持 HTML5 video 标签。

因为这个组件不需要渲染任何节点(这意味这组件本身不会被渲染到真实dom中,但是组件render函数创建的vnode会被渲染),只提供功能,所以作为抽象组件最合适不过。

抽象组件

在vue中为我们提供的抽象组件有:

他们的实现是一个对象,用于一个共同属性abstract: Boolean。当该属性为true时表明该组件时应该抽象组件。

通过抽象组件我们可以对其内部vnode做一些有趣的事情。

毫无疑问,在当前抽象组件构造函数中,我们访问this将会是会创建出来的实例。

我们在render函数中打印this时:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K1qfnYQV-1681820342974)(C:\Users\laster\Desktop\md\算法\643e82950d2dde5777be4ec8.jpg)]

会得到

接下来我们介绍即将用到的东西

在这之前,请先了解render函数。推荐一篇文章:[Vue抽象组件——所涉及的知识点](Vue抽象组件——所涉及的知识点 - 掘金 (juejin.cn))

  • this.$el:

    该属性存储了组件自身节点渲染完毕之后对应真实dom节点的引用(由此,只有在自身渲染完毕之后才能访问到$el属性,一般是mounted

  • this.$slots:

    相信用过slot的都不会陌生这个属性,该属性代表了通过槽传入组件的vnod,在我们最开始演示的时候那写法,其实可以写成:

    <sss-nexter>
        <slot name="default">
            <el-input></el-input>
            <el-input></el-input>
            <sss-button type="main" round>click me</sss-button>
        </slot>
    </sss-nexter>
    

通常我们在不使用slot时,其实是写在了默认slot当中,通过这个属性我们可以访问到所有传入组件的vnode

这个属性具有很多高阶用法,如果想具体了解可以参考这篇文章:[Vue 插槽(slot)使用(通俗易懂)](Vue 插槽(slot)使用(通俗易懂) - 掘金 (juejin.cn)) (不看也不影响我们继续

code

render

我们知道,在vue2中,一个组件只能渲染一个根元素,所以通常情况下,我们的组件都会被最外层div包裹,所以在抽象组件中,我们也要遵循这个规则。

那要是忘了写或者用的时候不想写怎么办?

那就需要我们手动添加一层div了,所以在render函数中:

    render() {
        const slots = this.$slots.default

        return slots.length > 1 ? h('div', slots) : slots
    },

在 Vue 中,h 函数是一个用来创建虚拟节点(VNode)的工具函数,它的全称是 createElement, 在这里我们只需要稍微了解h函数的作用就行。

mounted

在mounted函数中,我们通过this.$el来获取对应真实dom节点,在通过css选择器querySelectorAll来获取所有的input、button元素。

之后为每一个元素添加键盘enter事件即可。

当我在这里添加了键盘事件,在其他地方又添加了键盘事件,两者会覆盖么?

并不会,两者都会添加到该元素的键盘事件当中。

mounted() {
        //获取聚焦器内部所有特定元素
        const aimList = this.$el.querySelectorAll("input, button")

        //为元素添加事件
        for (let i = 0; i < aimList.length - 1; i++) {
            aimList[i].addEventListener("keyup", (e) => {
                if (e.key === 'Enter') {
                    e.preventDefault();
                    const next = i + 1;
                    aimList[next].focus();
                }
            })
        }
        //最后一个元素按下时失去焦点
        aimList[aimList.length-1].addEventListener("keyup",(e) => {
            if (e.key === 'Enter') {
                aimList[aimList.length-1].blur();
            }

        })

    }

完整code

/*
    聚焦器: 当input元素按下enter之后自动聚焦下一个元素
 */

import {h} from "vue"

export default {
    name: "sss-nexter",
    abstract: true,

    render() {

        const slots = this.$slots.default

        return slots.length > 1 ? h('div', slots) : slots
    },

    mounted() {
        //获取聚焦器内部所有特定元素
        const aimList = this.$el.querySelectorAll("input, button")

        //为元素添加事件
        for (let i = 0; i < aimList.length - 1; i++) {
            aimList[i].addEventListener("keyup", (e) => {
                if (e.key === 'Enter') {
                    e.preventDefault();
                    const next = i + 1;
                    aimList[next].focus();
                }
            })
        }
        //最后一个元素按下时失去焦点
        aimList[aimList.length-1].addEventListener("keyup",(e) => {
            if (e.key === 'Enter') {
                aimList[aimList.length-1].blur();
            }

        })

    }
}

end

作为第一个抽象组件,简单就行,主要为了了解抽象组件的写法。

      if (e.key === 'Enter') {
            aimList[aimList.length-1].blur();
        }

    })

}

}


# end

作为第一个抽象组件,简单就行,主要为了了解抽象组件的写法。

感谢看到最后😀
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值