V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
SuperMild
V2EX  ›  分享创造

基于 jQuery 用两个函数共约 10 行代码做了一个很像 Mithril.js 的前端框架 (非标题党)

  •  3
     
  •   SuperMild ·
    ahui2016 · 2021-03-04 09:51:30 +08:00 · 3377 次点击
    这是一个创建于 1120 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景

    大概一个月前看到一个 v 友发贴 ( https://v2ex.com/t/750181 ), 我第一次了解到 Mithril.js 这个框架,看了一下觉得不错,就打算用来改写自己一个小网站的前端页面。

    但使用过程中遇到一个小 bug 解决不了,也可能是我使用不当,具体原因不重要,总之结果是我烦了并且突然灵光一闪想到用 jQuery 也能像 Mithril 一样写网页,就试一了下,一试发现真的可以。

    为什么要模仿 Mithril ?

    • 在使用 jQuery 写小项目的时候,通常习惯写一部分 HTML, 然后再写 js 去操作 DOM, 但这样做不方便做组件。
    • 模仿了 Mithril 之后,完全不写 HTML, 一切都是 js, 因此非常轻松实现组件化,并且实际效果非常好,组件可以相互交流、可以嵌套、可以复用,在下面我会给出具体的示例。

    代码

    基于 jQuery, 再加上以下两个小函数,就是全部代码了。后面我会给出具体的使用示例。

    // 函数名 m 来源于 Mithril, 也可以理解为 make 的简称,用来创建一个元素。
    function m(name) {
      if (jQuery.type(name) == 'string') {
        return $(document.createElement(name));
      }
      return name.view();
    }
    
    // 函数名 cc 意思是 create a component, 用来创建一个简单的组件。
    function cc(name, id, elements) {
      if (!id) id = '' + Math.round(Math.random() * 100000000);
      const vnode = m(name).attr('id', id);
      if (elements) vnode.append(elements);
      return {id: '#'+id, raw_id: id, view: () => vnode};
    }
    

    简单示例 (与 Mithril 对比)

    Mithril 创建一个 component 是这样:

    const Hello = {
        view: () => m("div", [
            m("h1", {class: "title"}, "My first app"),
            m("button", "A button"),
        ])
    }
    

    而使用这个框架(以下简称 mj.js )创建一个 component 有两种方法,一是这样:

    const Hello = {
        view: () => m('div').append([
            m('h1').attr({class: 'title'}).text('My first app'),
            m('button').text('A button'),
        ])
    }
    

    也可以这样:

    const Hello = cc('div', 'hello', [
        m('h1').attr({class: 'title'}).text('My first app'),
        m('button').text('A button'),
    ]);
    

    可见,与 Mithril 的写法非常相似,同时又完全是 jQuery 的基本操作,只要会写 jq, 就完全没有学习难度。

    三个完整的例子

    Hello World

    Get User List

    uglynotes

    结语

    本框架虽然没啥技术含量,但真的好用,特别适合小项目,尤其是如果用过 Mithril.js 或习惯使用 jQuery, 可零学习成本获得一种前端解决方案,多一个选项。比其他框架易学,比 HTML + jQuery 的老办法更容易组织代码。

    项目仓库: https://github.com/ahui2016/mj.js

    第 1 条附言  ·  2021-03-05 20:50:46 +08:00
    我发现大家全都只看重函数 m, 但其实函数 cc 反而是更重要的,它是函数之间互相交流的重点所在,希望大家看看第二个例子 get user list 代码中我写的备注。
    第 2 条附言  ·  2021-05-07 22:06:22 +08:00

    再补充一个例子: mj.js + bootstrap 搭配使用方法 https://github.com/ahui2016/localtags/blob/main/public/home.html

    19 条回复    2021-03-05 20:56:14 +08:00
    tadebao
        1
    tadebao  
       2021-03-04 10:22:18 +08:00
    妙啊
    tikazyq
        2
    tikazyq  
       2021-03-04 10:27:25 +08:00   ❤️ 2
    妈妈不好了,对面那口棺材跳尸了!它似乎还在喊 “前端兴,JQ 王”!
    Austin2035
        3
    Austin2035  
       2021-03-04 10:29:39 +08:00
    Jquery! 永远滴神!
    Austin2035
        4
    Austin2035  
       2021-03-04 10:30:06 +08:00
    @lookcos jQuery
    Sunyanzi
        5
    Sunyanzi  
       2021-03-04 10:44:34 +08:00
    刚巧路过看到 ... 我觉得如果只是这样的话何必用到 jQuery ...

    我自己在用的有类似功能的代码如下 ... 也写了和你一样的示例 ...

    i.imgur.com/tY6tJYm.png

    优势是纯原生无任何依赖且使用时的语法更简单 ... 劣势是实现的代码超过十行了 ...

    名字的话 ... 既然你叫 m 那我叫 m2 好了 ... 一个不太成熟的小玩具供参考 ...
    gaoryrt
        6
    gaoryrt  
       2021-03-04 10:51:44 +08:00
    SuperMild
        7
    SuperMild  
    OP
       2021-03-04 11:06:04 +08:00
    @Sunyanzi jQuery 方便呀,后续组件需要发生变化的时候,addClass, css, show, hide 等等一大堆函数用起来太舒服了,原生 js 要多打很多字母。
    SuperMild
        8
    SuperMild  
    OP
       2021-03-04 11:12:11 +08:00
    @gaoryrt 虽然类似,但侧重点不同,你的工具生成 html 比我的方便、强大,但似乎不关心生成后的操作,而我的组件可以拥有自己的 method, 组件这宰也可以互相交流。
    SuperMild
        9
    SuperMild  
    OP
       2021-03-04 11:13:29 +08:00
    组件这宰 -> 组件之间
    oott123
        10
    oott123  
       2021-03-04 11:47:55 +08:00
    关于“生成元素”这个话题,我喜欢使用 crel : https://www.npmjs.com/package/crel
    当然这和楼主分享的并非一回事,只是顺便推荐~
    Shook
        11
    Shook  
       2021-03-04 12:21:27 +08:00
    @Sunyanzi 这个很酷,学习了
    ai277014717
        12
    ai277014717  
       2021-03-04 13:58:26 +08:00
    隐藏着 id 冲突的 bug 。
    brookepe
        13
    brookepe  
       2021-03-04 14:06:30 +08:00
    @SuperMild 按照你的思路 我加上了一些自己的想法 希望能给个 star
    {gayhub}/brooke1220/jquery.template
    SuperMild
        14
    SuperMild  
    OP
       2021-03-04 18:49:49 +08:00
    @ai277014717 id 问题可根据实际情况改用更小冲突的方法
    SuperMild
        15
    SuperMild  
    OP
       2021-03-04 18:51:48 +08:00
    @brookepe 已 star, 我本意也是抛砖引玉,提供一个思路,大家各自魔改着用~
    brookepe
        16
    brookepe  
       2021-03-04 19:52:44 +08:00
    @SuperMild 我把路由也加上了 /笑哭
    SuperMild
        17
    SuperMild  
    OP
       2021-03-04 20:45:24 +08:00
    @brookepe 路由好评呀
    charten
        18
    charten  
       2021-03-05 14:34:27 +08:00
    我也再写一个类似的,只不过我就直接用 jsx 写然后用 babel 转,比如
    const Hello = {
    view:()=><div><h1 class="title">My first app</h1><button>A button</button></div>

    }
    SuperMild
        19
    SuperMild  
    OP
       2021-03-05 20:56:14 +08:00
    @charten 如果使用 jquery, 就不需要 babel 了,html 是可以直接内嵌的,比如

    const Hello = {
    view:()=> $('<div><h1 class="title">My first app</h1><button>A button</button></div>')
    }

    但大家都误解了我这个东西,它的重点不是生成 html,而是组件与组件之间的交流,在生成 html 之后,组件还能互相交流。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   992 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 20:05 · PVG 04:05 · LAX 13:05 · JFK 16:05
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.