最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 原生JS SDK开发浅见

    正文概述 掘金(蓝色夜晚)   2021-07-28   532

    「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!」

    前言

    在开发JS SDK时,『原生 or 框架』不同人不同场景都有不同的选择。本文源于实际项目场景,阐述一些在原生环境下『不顺手』问题的处理。

    1. 模块化开发

    // index.js
    // 加入一个入口按钮
    // 按钮点击增加侧边栏
    // 点击空白隐藏侧边栏
    // 侧边栏点击出现弹窗
    // ...
    

    如此写下去想想都头秃,像一篇流水账作文。

    • 为了让读者快速定位到寻找的代码段,可以使用模块化(利用 webpack , gulp 等构建工具)。
    • 为了弱化组织逻辑的时间顺序,可以使用面向对象,比如拆分 Class (拆分的粒度可以借鉴对框架中组件的使用)。
    //index.js
    Class Entry {} // 入口按钮
    
    // dropdown.js
    Class Dropdown { // 为指定dom绑定侧边栏
        show() {} // 显示侧边栏
        hidden() {} // 隐藏侧边栏
        select() {} // 选中打开弹框
    }
    

    这里将组件开发的经验活用在了原生环境,代码结构更清晰了。

    2. 维护 innerHTML 的秩序

    <ul class="list">
        <li>1</li>
        <li>2</li>
        <li>3</li>
    </ul>
    

    用 JS 动态生成上面一段 dom 可能是这样的。

    const ul = document.createElement('ul');
    ul.className = 'list';
    ul.innerHTML = [1, 2, 3].map(i => `<li>${i}</li>`).join('');
    

    innerHTML 接受 HTML 序列化片段,因此我们可以使用模板字符串动态生成 dom 。不过这种方法存在局限性:

    1. 需要一个已有节点作为容器,无法在插入容器前操作 dom
    2. 容器节点的属性设置仍然需要手动添加(比如class);

    通过封装innerHTML可以克服上述局限性脱离容器生成一段 dom。

    const wrap = document.createElement('div');
    export const template2dom = <T extends HTMLElement>(template: string): T => {
        wrap.innerHTML = template;
        return wrap.children[0] as T;
    };
    
    const ul = template2dom(`
    <ul class="list">${
        [1, 2, 3].map(i => `<li>${i}</li>`).join('')
    }</ul>`);
    

    结合模块拆分可以将 dom 操作分为初始化渲染动态修改。使用封装的 template2dom 可以得到模块的根节点,在根节点下 querySelector 可获取动态修改的节点,使用原生 dom API操作。

    3. 清除事件

    使用框架时,我们可以不必关心自己监听的事件是不是该移除了,通常框架会替我们解决。现在需要我们来解决:

    • 当 dom 离开文档时,移除在其中绑定的事件;
    • 当 dom 内有频繁更且需要绑定事件的节点,使用事件委托

    知易行难,移除事件的位置通常与注册事件不在一起,为了获取监听函数和 dom 增加了很多在 class 中共享的属性;由于疏忽很可能遗漏某个 removeEventlistener 。封装一个事件管理类作为一个基类可以很好解决。

    export abstract class EventCleaner {
        private readonly eventMap = new Map <HTMLElement, Set<{
            name: keyof HTMLElementEventMap;
            cb(e: HTMLElementEventMap[keyof HTMLElementEventMap]): unknown;
        }>>();
        addEventListener<T extends keyof HTMLElementEventMap>(
            el: HTMLElement,
            name: T,
            cb: (e: HTMLElementEventMap[T]) => unknown
        ): void {
            el.addEventListener(name, cb);
            const events = this.eventMap.get(el);
            if (events) {
                events.add({name, cb});
            }
            else {
                this.eventMap.set(el, new Set([{name, cb}]));
            }
        }
        cleanEvent(): void {
            for (const [dom, events] of Array.from(this.eventMap)) {
                for (const {name, cb} of events) {
                    dom.removeEventListener(name, cb);
                }
            }
            this.eventMap.clear();
        }
    }
    

    这样只需要在每个派生类写入一个卸载方法,调用 cleanEvent ,即可清除该实例内监听的所有事件。

    4. 样式隔离

    样式隔离是 SDK 绕不开的问题。CSS Module 可在构建时修改 id 和 class 的形式,使得样式不会造成意外污染。

    • hash:CSS Module 默认class,丢失语义性随样式修改 (不利于下游覆盖样式)
    • local + name[md5]:兼顾语义性、唯一性且不会随样式修改。

    local + name\[md5\] 并不是 css-loader 支持的形式,需要在构建时提供 hash

    var md5 = require('md5');
    var affix = md5(path.parse(packageName)).slice(0, 5); // 将包名md5作为CssModule的后缀
    
    // webpack 配置
    {
        test: /\.css$/i,
        use: [
            'style-loader',
            {
                loader: 'css-loader',
                options: {
                    modules: {
                        localIdentName: `[local]_${affix}`,
                    }
                }
            }
        ]
    }
    

    以上是本人使用原生 JS 开发 SDK 的一些思考。其实主要围绕着梳理代码的秩序,原生API已足够强大不需要我扩展什么功能。前端框架给开发者更低的成本来养成逻辑清晰的习惯,也带来了一些思维惯性。希望能够取其精华弃其糟粕,无畏向前!

    源码参考:github.com/anyblue/blu…


    起源地下载网 » 原生JS SDK开发浅见

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元