博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Omi树组件omi-tree编写指南
阅读量:6348 次
发布时间:2019-06-22

本文共 5016 字,大约阅读时间需要 16 分钟。

能够以少量的代码声明式地编写可拖拽移动节点的树形组件。

通常树组件能够考验UI框架的健壮性,因为需要使用到UI框架的如下特性:

  • 组件嵌套
  • 组件传值
  • 组件批量传值
  • 组件依赖自身递归嵌套(nest-self)
  • 子、孙或炎黄子孙访问根组件实例

下面来介绍下使用 omi-tree 的开发全过程。你也可以无视文章,先体验一把和直接编辑源码试一把:

类划分

  • tree.js 树组件的根容器类,包含节点移动,根据id获取节点等通用方法,这里把其排除在tree-node之外
  • tree-node.js 树节点,自递归嵌套组件,因为tree-node中可以包含tree-node

树的数据规则:

{    name: 'Root',    children: [        {            name: 'A',            id: 1,            children: [                { id: 4, name: 'A1', children: [] },                { id: 7, name: 'A2', children: [] }            ]        },        {            name: 'B',            id: 2,            children: [                { id: 5, name: 'B1', children: [] },                { id: 8, name: 'B2', children: [] }            ]        },        {            name: 'C',            id: 3, children: [            { id: 6, name: 'C1', children: [] },            { id: 9, name: 'C2', children: [] }        ]        }    ]}

可以看到,每个节点都有唯一的id来标识,每个节点也有children属性来存放自己的子节点的信息。

组件HTML结构

tree结构:

  • 通过 o-repeat 生成所有 tree-node
  • group-data 把 data.children 的数据批量传递给各个 tree-node

这里需要特别注意的是:

  • o-repeat 等所有指令对应的 scope 数据是 this.data
  • group-data,data等等 的 scope 是 this

tree-node结构:

  • {
    {name}}
  • 可以看到每个tree-node都标记了draggable代表可以拖拽,drag和drop的支持情况大家可以caniuse一把。

    • 每个tree-node 既是拖拽对应,也是drop容器对象
    • li、div和ul都标记了 data-node-id 来存放id在dom元素上方便js里读取和传递

    完整代码解析

    先看tree:

    class Tree extends Omi.Component {    //移动节点    moveNode(id, parentId) {        if (id === parentId) {            return        }        if(this.check(parentId, id)) {            let parent = this.getChildById(parentId, this.data.children)            let child = this.removeChildById(id, this.data.children)            parent.children.push(child)            this.update()        }    }    //验证子节点的孩子节点是否包含父亲节点,这里主要是为了防止把父节点拖拽到自己的孩子节点当中,这是个错误的逻辑操作    check(parentId, childId){        let current = this.getChildById(childId, this.data.children),            children = current.children        for (let i = 0, len = children.length; i < len; i++) {            let child = children[i]            if (child.id === parentId) {                return false            }            let errorIds = this.check(parentId, child.id )            if (!errorIds) {                return false            }        }        return true    }    //根据id移除child节点数据    removeChildById(id, children) {        for (let i = 0, len = children.length; i < len; i++) {            let child = children[i]            if (child.id === id) {                children.splice(i, 1)                return child            }            let target = this.removeChildById(id, child.children)            if (target) {                return target            }        }    }    //根据id获取child节点数据    getChildById(id, children) {        for (let i = 0, len = children.length; i < len; i++) {            let child = children[i]            if (child.id === id) {                return child            }            let target = this.getChildById(id, child.children)            if (target) {                return target            }        }    }    render() {        return `
    ` }}//生成标签用于声明式嵌入其他组件Omi.tag('tree', Tree)

    下面来看 tree-node:

    class TreeNode extends Omi.Component {    dropHandler(evt) {        //通过evt.dataTransfer.getData接收传递过来的数据        this.getRootInstance(this.parent).moveNode(parseInt(evt.dataTransfer.getData("node-id")), parseInt(evt.target.dataset['nodeId']))        this.node && this.node.classList.remove('drag-over')        evt.stopPropagation()        evt.preventDefault()    }    getRootInstance(parent){        if(parent.moveNode){            return parent        }else{            return this.getRootInstance(parent.parent)        }    }    dragOverHandler(evt){        this.node.classList.add('drag-over')        evt.stopPropagation()        evt.preventDefault()    }    dragLeaveHandler(){        this.node.classList.remove('drag-over')    }        dragStartHandler(evt){        //设置要传递的数据        evt.dataTransfer.setData("node-id",this.data.id)        evt.stopPropagation()    }        //局部样式,drag-over是拖拽在node之上的一个激活样式    style(){        return `            .drag-over{                border:1px dashed black;            }        `    }    render(){        return `                
  • {
    {name}}
  • ` }}//生成标签用于声明式嵌入其他组件Omi.tag('tree-node',TreeNode)
    • dragStart的时候通过evt.dataTransfer.setData设置需要传递的数据,这里存放了拖拽的节点id
    • drop的时候通过evt.dataTransfer.getData读取传递过来的数据,这里取drag的node的节点id
    • 通过 o-if="children.length > 0" 决定是否生成 ul 标签
    • getRootInstance组件是递归去调取tree的对象的实例(因为tree-node可能包含tree-node,所以需要递归读parent)
    • 拿到tree的实例之后,调用tree的对象的实例的moveNode方法去移动节点,moveNode的本质就是修改节点数据,然后update组件

    到此位置,复杂的拖拽移动都完成了。增删改查就更加简单了,大家可以接着试试~~~

    Omi相关

    • Omi官网
    • Omi的Github地址
    • 如果想体验一下Omi框架,可以访问
    • 如果想使用Omi框架或者开发完善Omi框架,可以访问
    • 如果你想获得更佳的阅读体验,可以访问
    • 如果你懒得搭建项目脚手架,可以试试
    • 如果你有Omi相关的问题可以
    • 如果想更加方便的交流关于Omi的一切可以加入QQ的Omi交流群(256426170)

    转载地址:http://yfvla.baihongyu.com/

    你可能感兴趣的文章
    国家为何如此重视石墨烯?
    查看>>
    《Python和Pygame游戏开发指南》——1.14 配套网站上的更多信息
    查看>>
    Kafka+Flink 实现准实时异常检测系统
    查看>>
    利用mybatis查询两级树形菜单
    查看>>
    《慕客网:IOS基础入门之Foundation框架初体验》学习笔记 <一>
    查看>>
    Spring声明式事务管理之二:核心接口API
    查看>>
    解决:在微信中访问app下载链接提示“已停止访问该网页”
    查看>>
    LNMP环境安装(二)
    查看>>
    MFC对话框编程-图片控件
    查看>>
    nodejs启动webserver服务
    查看>>
    小偷被抓叫嚣:我不偷警察没饭吃
    查看>>
    python初学—-实现excel里面读数据进行排序
    查看>>
    用户体验升级后 “谁行谁上”让百度Q4财报更有底气
    查看>>
    直播相关学习链接
    查看>>
    使用RPM包工具和源码包编译安装Linux应用程序
    查看>>
    VoIP——开启免费通话新时代的先锋
    查看>>
    Linux下rsync的用法
    查看>>
    apache虚拟主机、日志轮询、日志统计、去版本优化
    查看>>
    java代码实现开启openoffice服务和关闭sffice.exe进程
    查看>>
    docker镜像的使用方法
    查看>>