用数据驱动框架vandf创建dropdown组件

91 阅读3分钟

用数据驱动框架vandf创建dropdown组件

​ vandf是开源的数据驱动开发框架,非常容易创建可重用的响应式组件,话不多说,直接动手撮代码(其中的css使用了tailwind CSS)。

1.安装vandf库

npm i vandf

2.定义组件

​ Van是一个基础组件类,可以通过继承或直接调用的方式来使用,通过它的实例进行一些配置,具体的使用方法可以参考github仓库的使用文档:github.com/abbasky/van…

import {Van} from "vandf";
class Dropdown extends Van {
    constructor(id){
        super(id)
        //注册视图模型
        this.view(DropdownView)
		//创建一个按钮
        let button = this.kid('button')//定义一个子名称为’button‘的子组件
        	.tag('button')//element的类型tagName为'button'
        	.view(ButtonView)//注册视图模型
        	.html('Dropdown')//设置dropdown的按钮标签
        //创建一个弹出层
        let popper = this.kid('popper-list').view(PopperView)
        //创建一个选项列表
        popper.kid('list-item')
            .tag('a')
            .view(ListItemView)
            .model(ListItemModel)//
    }
}

3.创建Dropdown视图模型

class DropdownView {
    constructor(){
        //定义一个弹出层的状态
        this._states = {display:false}
    }
    states(){
        //返回状态,将状态向子层传递
        return this._states;
    }

    create (node) {
        //注册全局click事件,在禁止选项列表click事件时
        //可以认为非dropdown的click事件,此时隐藏弹出层。
        node.addEventListener('click', e => {
            if(!this._states.display){return}
            this._states.display = false;
            node.update();
        })
        //接受选项选中的事件
        .on('selected', e => {
            console.log(e.data)
        })
    }
}

4.创建Button视图模型

class ButtonView {

    states(s) {
        //接收父组件的状态,通过接收父组件的状态实现状态共享
        this._states = s;
    }

    create (node) {
        node.on('click', e => {
            //停止原生“click”事件冒泡
            e.rawEvent.stopPropagation();
            //修改状态
            this._states.display = !this._states.display;
            //更新父组件,因为弹出层在父组件的子组件,而非Button组件的子组件。
            node.parent().update()            
        },true)//传递true参数,注册原生事件。
    }
}

//图标视图模型
class IconPathView {
    constructor(_, config) {
        //接收配置信息,配置信息中含有图标的path值
        this._config = config;
    }

    //通过渲染,将配置信息中icon的path值
    render(node){
        let c = this._config;
        node.attr('d', c.icon)
    }
}

5.定义弹出层视图模型

class PopperView {
    states(s) {
        //接收父层传递的状态值
        this._states = s;
    }

    render (node) {
        //根据display状态值设置弹出层弹出或隐藏状态
        node.classed('hidden', !this._states.display)
    }
}

6.定义选项列表的数据模型和视图模型

class ListItemModel{
    constructor(){
        this._selIndex = undefined;
    }

    get selIndex (){return this._selIndex}

    get selItem () {return this._selIndex ? this._items[this._selIndex] : undefined}
	//supply可以接收顶层一层层传递的数据d,返回值为提取的数组
    supply(d) {
        this._items = d.list;
        return d.list
    }

    selected(index) {this._selIndex = index}

}

class ListItemView {
    constructor(model){
        this._model = model;
    }

    create (node,i){
        node.on('click', e => {
            this._model.selected(i);
            node.emit('selected', this._model.selItem)
        }, true)
    }

    render(node, d, i){
        node.text(d)
            .classed('bg-blue-100', this._model.selIndex === i)
    }
}

7.准备数据

const data = [
    "Your Profile",
    "Your Projects",
    "Help",
    "Settings",
    "Sign Out"
]

const down = "M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"

8.使用组件

let app = Van.new('app')

Dropdown.new('dropdown', app.id)
    .supply({list:data})
    .config({icon:down})

app.attach(document.querySelector("#app"))

9.总结

​ 用vandf开发的组件,组件的定义、数据模型、视图模型完全结构,每一部分都是可重用的,组合起来也是可重用的,非常适合组件的开发。组件之间可以通过事件、状态共享、配置等实现数据通信,可以非常容易的实现低耦合,高可用的组件开发,且运行效率极高,大家不妨一试。