1. 程式人生 > >Omi樹元件omi-tree編寫指南

Omi樹元件omi-tree編寫指南

Omi框架能夠以少量的程式碼宣告式地編寫可拖拽移動節點的樹形元件。
通常樹元件能夠考驗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結構:

<ul>
  <tree-node o-repeat="child in children" group-data="data.children"></tree-node>
</ul>
  • 通過 o-repeat 生成所有 tree-node
  • group-data 把 data.children 的資料批量傳遞給各個 tree-node

這裡需要特別注意的是:

  • o-repeat 等所有指令對應的 scope 資料是 this.data
  • group-data,data等等 的 scope 是 this

tree-node結構:

<li data-node-id="{{id}}"  draggable="true"  ondragstart="dragStartHandler" ondragleave="dragLeaveHandler"  ondrop="dropHandler" ondragover="dragOverHandler" >
    <div data-node-id="{{id}}">{{name}}</div>
    <ul data-node-id="{{id}}" o-if="children.length > 0">
        <tree-node o-repeat="child in children" group-data="data.children"></tree-node>
    </ul>
</li>

可以看到每個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 `<ul>
                  <tree-node o-repeat="child in children" group-data="data.children"></tree-node>
              </ul>`
    }
}

//生成標籤用於宣告式嵌入其他元件
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 `
                <li data-node-id="{{id}}"  draggable="true"  ondragstart="dragStartHandler" ondragleave="dragLeaveHandler"  ondrop="dropHandler" ondragover="dragOverHandler" >
                    <div data-node-id="{{id}}">{{name}}</div>
                    <ul data-node-id="{{id}}" o-if="children.length > 0">
                        <tree-node o-repeat="child in children" group-data="data.children"></tree-node>
                    </ul>
                </li>
            `
    }
}

//生成標籤用於宣告式嵌入其他元件
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框架,可以訪問 Omi使用文件
  • 如果你想獲得更佳的閱讀體驗,可以訪問 Docs Website
  • 如果你懶得搭建專案腳手架,可以試試 omi-cli
  • 如果你有Omi相關的問題可以 New issue
  • 如果想更加方便的交流關於Omi的一切可以加入QQ的Omi交流群(256426170)

相關推薦

Omi元件omi-tree編寫指南

Omi框架能夠以少量的程式碼宣告式地編寫可拖拽移動節點的樹形元件。 通常樹元件能夠考驗UI框架的健壯性,因為需要使用到UI框架的如下特性: 元件巢狀 元件傳值 元件批量傳值 元件依賴自身遞迴巢狀(nest-self) 子、孫或炎黃子孫訪問根元件例項 下面來介紹下使用 omi-tree 的開發全過程。你也可

[Vue.js — iView — Tree] 點選元件父節點名稱時展開、收縮後代節點

適用於iview tree。 ``` <Tree ref="tree" :data="data" :load-data="loadData" @on-select-change="selectChange" show-checkbox/> ``` ``` data() {

Omi教程-元件通訊攻略大全

元件通訊 Omi框架組建間的通訊非常遍歷靈活,因為有許多可選方案進行通訊: 通過在元件上宣告 data-* 傳遞給子節點 通過在元件上宣告 data 傳遞給子節點 (支援複雜資料型別的對映) 父容器設定 childrenData 自動傳遞給子節點 宣告 group-data 傳遞(支援複雜資料型別的對映)

easyui tree元件無限迴圈

在學習jquery easyui的tree元件的時候,在url為連結地址的時,發現如果最後一個節點的state為closed時,未節點顯示為資料夾,單擊會重新載入動態(Url:連結地址)形成無限迴圈。如: tree.json [{ "id":1,

BZOJ 2631 tree 動態(Link-Cut-Tree)

數據 val string sta root 樹形 () print access 題目大意:維護一種樹形數據結構。支持下面操作: 1.樹上兩點之間的點權值+k。 2.刪除一條邊。添加一條邊,保證加邊之後還是一棵樹。 3.樹上兩點之間點權值*k。 4.詢問樹上兩點時間點

sqlmap-tamper編寫指南

pos firebird gre message nor quotes .py 代碼 內置 註:最近遇到了一些奇怪的waf,想自己寫一些tamper但是發現沒有參考材料可以使用,因此在寫了這篇文章,一方便進行自定義的tamper編寫。筆者筆力有限,如有錯誤,敬請讀者們指正。

【bzoj4605】嶗山白花蛇草水 權值線段套KD-tree

復雜 接下來 efi ora 這也 多少 線段樹 會有 如果 題目描述 神犇Aleph在SDOI Round2前立了一個flag:如果進了省隊,就現場直播喝嶗山白花蛇草水。憑借著神犇Aleph的實力,他輕松地進了山東省省隊,現在便是他履行諾言的時候了。蒟蒻Bob特地為他準

決策(Decision Tree)SkLearn

true predict mat ray int lec pytho next() action #!/usr/bin/env python # -*- coding: utf-8 -*- from sklearn.feature_extraction import Di

設備(Device Tree

輸出 mpat vim ring 開源協議 add kernel 匹配 dev 設備樹介紹: 設備樹是一個描述設備硬件資源的文件,該文件是由節點組成的樹形結構。如下: / { node1 { a-string-property = "A string"; a-string-

ARM Linux 3.x的設備(Device Tree)宋寶華

3rd else 命名 number 部分 kernel 傳統 rtc trigge 1. ARM Device Tree起源 Linus Torvalds在2011年3月17日的ARM Linux郵件列表宣稱“this whole ARM thing is a f*

【Spark MLlib速成寶典】模型篇05決策【Decision Tree】(Python版)

back filter oms sse mlu eval ffffff size red 目錄   決策樹原理   決策樹代碼(Spark Python) 決策樹原理   詳見博文:http://www.cnblogs.com/itmorn/p/79

決策(decision tree

方法 生成算法 ogr np完全 信息熵 cti 標記 ges 樹形 決策樹是一種基本的分類和回歸方法。本章主要討論用於分類的決策樹,決策樹模型呈樹形結構,在分類問題中,表示基於特征對實例進行分類的過程,它可以認為是if-then規則的集合,也可以認為是定義在特征空間與類空

決策(decision tree)

from ase size eat for pan ted count import 代碼還好懂,但是後面選擇更好的劃分數據集的方法,有點不知道為什麽那樣選。 還要好好理解推導。 from math import log #計算香農熵 def calcShannonEnt

通達OA應用中心使用手冊(腳本編寫指南)

cit ted 點擊 ble 計算 文本 ppp 必須 組合 腳本編寫必備基礎 1.1 什麽是腳本 腳本是一段 PHP 代碼,可以被應用中心執行以實現特定功能。應用中心支持通過腳本 實現以下功能: 自定義計算函數。 自定義提取觸發

平衡二叉Balanced Binary Tree

play trees define 分享圖片 gif gpo -c complex 沒有 [抄題]: Given a binary tree, determine if it is height-balanced. For this problem, a height-ba

矩陣定理(Matrix Tree)學習筆記

cstring 相關 () str eof bsp lld open csdn 如果不談證明,稍微有點線代基礎的人都可以在兩分鐘內學完所有相關內容。。 行列式隨便找本線代書看一下基本性質就好了。 學習資源: https://www.cnblogs.com/candy99/p

紅黑( Red-Black Tree ) - 筆記

沖突 性能 tro 紅黑樹特性 最短路徑 方式 筆記 nbsp 一個 1. 紅黑樹屬性:根到葉子的路徑中,最長路徑不大於最短路徑的兩倍。 2. 紅黑樹是一個二叉搜索樹,並且有   a. 每個節點除了有左、右、父節點的屬性外,還有顏色屬性,紅色或者黑色。   b. ( 根屬

決策(Decision Tree)原理

範圍 思想 選擇 規則 是我 概念 而是 tree 個人 決策樹的思想在生活中很常見,其實就是根據條件去做決定,選擇最符合我們自己東西,例如買房子,我們要考慮的有城市/地段/是否有地鐵/開發商/戶型等等這些因數,這些因數在我們決策樹中就叫做特征,我們就是根據這些特

平衡二叉(Balanced Binary Tree 或 Height-Balanced Tree)又稱AVL

binary strong 但是 inf ++i 平衡二叉樹 data 效率 assert 平衡二叉樹(Balanced Binary Tree 或 Height-Balanced Tree)又稱AVL樹 (a)和(b)都是排序二叉樹,但是查找(b)的93節點就需要查找6

windows基線編寫指南-powershell版

csdn copy event cedit off https error ping 讀取配置 前言: 因為工作的原因,要寫windows下的基線檢查腳本。之前沒接觸過,在網上找了半天也沒找到現成的,無奈只好自己研究,最後還是成功完成了工作。 在我編寫之後發現wi