上一主题 下一主题
ScriptCat,新一代的脚本管理器脚本站,与全世界分享你的用户脚本油猴脚本开发指南教程目录
12下一页
返回列表 发新帖

脚本猫UI库初版

[复制链接]
  • TA的每日心情
    开心
    2024-11-21 13:37
  • 签到天数: 213 天

    [LV.7]常住居民III

    305

    主题

    4215

    回帖

    4073

    积分

    管理员

    积分
    4073

    管理员荣誉开发者油中2周年生态建设者喜迎中秋油中3周年挑战者 lv2

    发表于 2023-6-26 10:45:57 | 显示全部楼层 | 阅读模式

    书接上文

    脚本猫UI库API设计提案
    https://bbs.tampermonkey.net.cn/thread-4711-1-1.html
    (出处: 油猴中文网)

    初版完成了,越写越觉得是React了,有点陷入迷茫,希望哥哥们评价一下:

    相比直接react的优点

    • 直接require即可使用
    • 处理了shadowDom之类的问题,不会有样式冲突
    • 不需要打包工具

    迷茫的点

    • 本意是一个UI框架,快速开发一个窗口,但是变成了组件的封装,需要自己组合,写起来感觉又变麻烦了
      • 这个问题可能后面需要写一个模板,但是模板怎么去写,还不知道
    • 越写越像React,本来希望简单,现在看起来反而复杂了(虽然也有写一个页面就是需要这么去写的原因,可能只能再做一些封装了)

    示例代码如下:

    https://github.com/scriptscat/lib/tree/main/example

    image.png

    const data = { input: "默认值" };
    
    CAT_UI.createPlan({
        header: {
            title: "脚本猫的UI框架",
        },
        footer: {
            version: "0.1.0",
        },
        render() {
            const [input, setInput] = CAT_UI.useState(data.input);
            return CAT_UI.Space([
                CAT_UI.Text("脚本猫的UI框架: " + input),
                CAT_UI.Button("我是按钮", {
                    type: "primary",
                    onClick() {
                        CAT_UI.Message.info("我被点击了,你输入了: " + input);
                    }
                }),
                CAT_UI.Input({
                    value: input,
                    onChange(val) {
                        setInput(val);
                        data.input = val;
                    }
                }),
                CAT_UI.Checkbox("我是复选框"),
                CAT_UI.Select([
                    CAT_UI.Select.Option("选项1"),
                    CAT_UI.Select.Option("选项2"),
                ]),
                CAT_UI.createElement("div", {
                    style: {
                        display: "flex",
                        justifyContent: "space-between",
                        alignItems: "center"
                    }
                }, CAT_UI.Text("请输入"), CAT_UI.Input({
                    value: input,
                    onChange(val) {
                        setInput(val);
                        data.input = val;
                    },
                    style: {
                        flex: 1
                    }
                }))
            ], {
                direction: "vertical"
            });
        },
        onReady(plan) {
            plan.onDraggableStop((e) => {
                console.log(e)
            });
        }
    });
    
    CAT_UI.Message.success("你好,脚本猫");

    点评

    迷茫可能在定位有问题,现在感觉就是做一个基础的UI框架,有一些基础的组件和功能,模板之类的由其他作者开发模板库再使用  发表于 2023-6-26 11:55
    上不慕古,下不肖俗。为疏为懒,不敢为狂。为拙为愚,不敢为恶。
  • TA的每日心情
    慵懒
    半小时前
  • 签到天数: 822 天

    [LV.10]以坛为家III

    31

    主题

    553

    回帖

    1564

    积分

    荣誉开发者

    积分
    1564

    荣誉开发者新人进步奖油中2周年生态建设者新人报道挑战者 lv2油中3周年喜迎中秋

    发表于 2023-6-26 10:54:37 | 显示全部楼层
    本意是一个UI框架,快速开发一个窗口,但是变成了组件的封装,需要自己组合

    目前是一个组件生成一个shadowDOM,因此每个组件都要单独封装,
    能不能所有组件共用一个shadowDOM,这样就可以不用封装了?
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2024-11-21 13:37
  • 签到天数: 213 天

    [LV.7]常住居民III

    305

    主题

    4215

    回帖

    4073

    积分

    管理员

    积分
    4073

    管理员荣誉开发者油中2周年生态建设者喜迎中秋油中3周年挑战者 lv2

    发表于 2023-6-26 11:00:04 | 显示全部楼层
    steven026 发表于 2023-6-26 10:54
    目前是一个组件生成一个shadowDOM,因此每个组件都要单独封装,
    能不能所有组件共用一个shadowDOM,这样就 ...

    所有组件共用一个shadowDOM也还是要封装UI组件,哥哥封两个普通的组件就明白了

    只是刚好Message和Notification要那样做
    上不慕古,下不肖俗。为疏为懒,不敢为狂。为拙为愚,不敢为恶。
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2022-3-8 11:41
  • 签到天数: 2 天

    [LV.1]初来乍到

    22

    主题

    883

    回帖

    1381

    积分

    荣誉开发者

    积分
    1381

    荣誉开发者卓越贡献油中2周年生态建设者油中3周年挑战者 lv2

    发表于 2023-6-26 23:39:00 | 显示全部楼层
    模板字符串的方案如何:
    1. return CAT_UI.jsx({
    2.     input: data.input,
    3.     inputChange: setInput,
    4.     buttonClick() {
    5.         CAT_UI.Message.info("我被点击了,你输入了: " + data.input);
    6.     },
    7. })`
    8. <Space>
    9.     <Text>脚本猫的UI框架: ${'input'}</Text>
    10.     <Button type="primary" onClick=${'buttonClick'}>我是按钮</Button>
    11.     <Input value=${'input'} onChange=${'inputChange'}></Input>
    12.     <Checkbox>我是复选框</Checkbox>
    13.     <Select>
    14.         <Option>选项1</Option>
    15.         <Option>选项2</Option>
    16.     </Select>
    17.     <div style="display: flex; justify-content: space-between; align-items: center;">
    18.         <Text>请输入:</Text>
    19.         <Input value=${'input'} onChange=${'inputChange'} style="flex: 1;"></Input>
    20.     </div>
    21. </Space>
    22. `;
    复制代码

    规定库节点以大写字母开头,原生节点全小写,允许混用。函数设计割裂的问题,也许可以允许简单的函数直接写在jsx里?CAT_UI.jsx构造一个标签函数,通过字符串类型的参数来传值(或者不传值直接${函数}然后在标签函数里处理?语义上有点怪),可能得用上AST,实现难度大一点。
    已有1人评分好评 油猫币 理由
    王一之 + 1 + 4 ggnb!

    查看全部评分 总评分:好评 +1  油猫币 +4 

    回复

    使用道具 举报

  • TA的每日心情
    开心
    2024-11-21 13:37
  • 签到天数: 213 天

    [LV.7]常住居民III

    305

    主题

    4215

    回帖

    4073

    积分

    管理员

    积分
    4073

    管理员荣誉开发者油中2周年生态建设者喜迎中秋油中3周年挑战者 lv2

    发表于 2023-6-27 00:35:08 | 显示全部楼层
    cxxjackie 发表于 2023-6-26 23:39
    模板字符串的方案如何:

    规定库节点以大写字母开头,原生节点全小写,允许混用。函数设计割裂的问题,也许 ...

    这样实现有点复杂,想不到怎么实现

    有点怪怪的vue的样子的
    上不慕古,下不肖俗。为疏为懒,不敢为狂。为拙为愚,不敢为恶。
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2024-11-21 13:37
  • 签到天数: 213 天

    [LV.7]常住居民III

    305

    主题

    4215

    回帖

    4073

    积分

    管理员

    积分
    4073

    管理员荣誉开发者油中2周年生态建设者喜迎中秋油中3周年挑战者 lv2

    发表于 2023-6-27 00:37:37 | 显示全部楼层
    cxxjackie 发表于 2023-6-26 23:39
    模板字符串的方案如何:

    规定库节点以大写字母开头,原生节点全小写,允许混用。函数设计割裂的问题,也许 ...

    可能想要不就先按现在的来吧,实现出来再说,这个也是基础框架,最终提供给用户(开发者)来用的可能是封装程度更高的方法,用起来可能就还好些了

    上不慕古,下不肖俗。为疏为懒,不敢为狂。为拙为愚,不敢为恶。
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2022-3-8 11:41
  • 签到天数: 2 天

    [LV.1]初来乍到

    22

    主题

    883

    回帖

    1381

    积分

    荣誉开发者

    积分
    1381

    荣誉开发者卓越贡献油中2周年生态建设者油中3周年挑战者 lv2

    发表于 2023-6-27 23:32:00 | 显示全部楼层
    王一之 发表于 2023-6-27 00:35
    这样实现有点复杂,想不到怎么实现

    有点怪怪的vue的样子的

    简单方案就是先字符串处理转换成React的jsx,再通过Babel翻译成React.createElement,这样打包出来应该很大。自己实现的话我想到的是DOMParser,把jsx当成xml解析,再通过DOM操作转换成真正的元素,这样应该可以去掉React依赖。传值问题我想了想还是用React那种格式比较合适,模板取值的话还得做一遍替换,有点多此一举了。
    1. let str = `
    2. <Space>
    3.     <Text>脚本猫的UI框架: {input}</Text>
    4.     <Button type="primary" onClick={buttonClick}>我是按钮</Button>
    5.     <Input value={input} onChange={inputChange}></Input>
    6.     <Checkbox>我是复选框</Checkbox>
    7.     <Select>
    8.         <Option>选项1</Option>
    9.         <Option>选项2</Option>
    10.     </Select>
    11.     <div style="display: flex; justify-content: space-between; align-items: center;">
    12.         <Text>请输入:</Text>
    13.         <Input value={input} onChange={inputChange} style="flex: 1;"></Input>
    14.     </div>
    15. </Space>
    16. `
    17. str = str.replace(/(?<=<[^>]+=)\{[^>} ]+\}/g, '"$&"'); // 处理引号问题
    18. const dom = new DOMParser().parseFromString(str, 'text/xml');
    19. console.log(dom);
    复制代码
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2024-11-21 13:37
  • 签到天数: 213 天

    [LV.7]常住居民III

    305

    主题

    4215

    回帖

    4073

    积分

    管理员

    积分
    4073

    管理员荣誉开发者油中2周年生态建设者喜迎中秋油中3周年挑战者 lv2

    发表于 2023-6-28 00:05:50 | 显示全部楼层
    cxxjackie 发表于 2023-6-27 23:32
    简单方案就是先字符串处理转换成React的jsx,再通过Babel翻译成React.createElement,这样打包出来应该很 ...

    确实,如果都可以jsx了的话,{}这样传值也没啥必要了

    然后就是字符串模板的话,不好做自动提示,也不好给webpack之类的打包工具使用

    我和@steven026 写了一个demo(初版了),c大要不要试试:

    https://github.com/scriptscat/lib/blob/main/example/ui.user.js

    后面的话,感觉就加强封装之类的,尽量简单使用
    上不慕古,下不肖俗。为疏为懒,不敢为狂。为拙为愚,不敢为恶。
    回复

    使用道具 举报

  • TA的每日心情
    慵懒
    2022-3-8 11:41
  • 签到天数: 2 天

    [LV.1]初来乍到

    22

    主题

    883

    回帖

    1381

    积分

    荣誉开发者

    积分
    1381

    荣誉开发者卓越贡献油中2周年生态建设者油中3周年挑战者 lv2

    发表于 2023-6-29 23:02:56 | 显示全部楼层
    王一之 发表于 2023-6-28 00:05
    确实,如果都可以jsx了的话,{}这样传值也没啥必要了

    然后就是字符串模板的话,不好做自动提示,也不好 ...

    这个我看过了,没有摆脱React依赖,我还是更想要一个原生的,因为创建元素和绑定数据这些都不难,搞一个React进来有点太大了,很多东西用不到。
    撸了个解析模板字符串的简单实现出来,这个即使不采用,应该也可以做成模块,API对接一下就行了:
    1. function parseData(data, value) {
    2.     const arr = value.split(/({[^}]+})/);
    3.     for (let i = 0, l = parseInt(arr.length / 2); i < l; i++) {
    4.         const key = arr[2 * i + 1].slice(1, -1);
    5.         if (key in data) {
    6.             arr[2 * i + 1] = data[key];
    7.         }
    8.     }
    9.     let result;
    10.     arr.forEach(v => {
    11.         if (v === '') return;
    12.         result = result ? result + v : v;
    13.     });
    14.     return result;
    15. }
    16. function createNode(data, node) {
    17.     const attrs = {};
    18.     for (const attr of node.attributes) {
    19.         attrs[attr.name] = parseData(data, attr.value);
    20.     }
    21.     let text = '';
    22.     const children = [];
    23.     for (const child of node.childNodes) {
    24.         if (child.nodeType === 3) {
    25.             text += child.nodeValue.trim();
    26.         } else {
    27.             children.push(createNode(data, child));
    28.         }
    29.     }
    30.     text = parseData(data, text);
    31.     return {
    32.         tag: node.tagName,
    33.         text: text,
    34.         attributes: attrs,
    35.         children: children
    36.     };
    37. }
    38. function jsx(data, str) {
    39.     str = str.replace(/(?<=<[^>]+=)\{[^>} ]+\}/g, '"$&"');
    40.     const dom = new DOMParser().parseFromString(str, 'text/xml');
    41.     const nodes = [];
    42.     for (const node of dom.children) {
    43.         nodes.push(createNode(data, node));
    44.     }
    45.     return nodes.length > 1 ? nodes : nodes[0];
    46. }

    47. const data = { input: "默认值" };
    48. const result = jsx({
    49.     input: data.input,
    50.     inputChange(val) {
    51.         data.input = val;
    52.     },
    53.     buttonClick() {
    54.         alert("我被点击了,你输入了: " + data.input);
    55.     }}, `
    56. <Space>
    57.     <Text>脚本猫的UI框架: {input}</Text>
    58.     <Button type="primary" onClick={buttonClick}>我是按钮</Button>
    59.     <Input value={input} onChange={inputChange}></Input>
    60.     <Checkbox>我是复选框</Checkbox>
    61.     <Select>
    62.         <Option>选项1</Option>
    63.         <Option>选项2</Option>
    64.     </Select>
    65.     <div style="display: flex; justify-content: space-between; align-items: center;">
    66.         <Text>请输入:</Text>
    67.         <Input value={input} onChange={inputChange} style="flex: 1;"></Input>
    68.     </div>
    69. </Space>
    70. `);
    71. console.log(result);
    复制代码
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2024-11-21 13:37
  • 签到天数: 213 天

    [LV.7]常住居民III

    305

    主题

    4215

    回帖

    4073

    积分

    管理员

    积分
    4073

    管理员荣誉开发者油中2周年生态建设者喜迎中秋油中3周年挑战者 lv2

    发表于 2023-6-29 23:32:26 | 显示全部楼层
    cxxjackie 发表于 2023-6-29 23:02
    这个我看过了,没有摆脱React依赖,我还是更想要一个原生的,因为创建元素和绑定数据这些都不难,搞一个R ...

    woc nb,好像也是可以直接转换一下

    直接使用react的主要原因是UI框架可以直接用,而不用自己写了,确实是有点大了,不过现在暂时不考虑这个,如果要缩小的话,要自己去写UI样式之类的,然后也有一个小型的类似react的框架可以选择:https://github.com/vanjs-org/van

    上不慕古,下不肖俗。为疏为懒,不敢为狂。为拙为愚,不敢为恶。
    回复

    使用道具 举报

    发表回复

    本版积分规则

    快速回复 返回顶部 返回列表