AnguarJS directive调用外部函数

需求

angular-ui bootstrap提供了很多重写过bootstrap的组件,利用的就是AngularJS自定义指令directive。但是其实,很多组件都已经有别的框架写好了,比如jQuery的jquery-ui等等。所以,我有个想法,能不能利用这些已经存在组件,组装一个适配AngularJS的控件呢。因此做如下尝试,将bootstrap-treeview做一个适配AngularJS的,达到预期效果。

利用到的框架

  1. requirejs
  2. jquery
  3. bootstrap
  4. bootstrap-treeview

bootstrap-treeview简介

bootstrap-treeview是一个jquery的插件组件,是个树状结构数据展示组件,树结构的样式依赖bootstrap,官方的截图如下:

AnguarJS directive调用外部函数_第1张图片
bootstrap-treeview

bootstrap-treeview 参数配置

{
    enableLinks: true, // 树节点是否可以链接,即生成一个a标签
    showTags: true,    // 树节点最右边是否显示badge
    data: []           // 数据源,必须为一个数组
}

bootstrap-treeview 数据源格式

data: [{
    text: 'node',
    href: 'javascript:void(0)',  // enableLinks === false 不起作用
    tags: [10],                  // tags 可以不需要,showTags === false 不起作用
    nodes: [
        // 子节点,与父节点格式一致,如果没有子节点,可以为空值
        {
            text: 'subnode',
            href: '#/nodes.json',
        }
        // ......
    ]
}]

bootstrap-treeview基本用法

  1. 页面添加标签
  1. 创建treeview组件
$(function () {
    var data = [{
        text: 'parent',
        href: 'javascript:void(0);',
        tags: [2],
        nodes: [{
            text: 'child1',
            href: '#/children/1.json',
        }, {
            text: 'child2',
            href: '#/children/2.json',
        }]

    }]
    var options = {
        enableLinks: true,
        showTags: true,
        data: data
    };

    $('div#treeView').treeview(options);
})

显示效果如下图所示:

AnguarJS directive调用外部函数_第2张图片
treeview示例

适配方法添加

因为 bootstrap-treeview 只能在初始化的时候,设置数据源,因此给bootstrap-treeview加入一个方法 setData,具体实现如下:

Tree.prototype.setData = function(data) {
    this.options.data = data;
    this.init(this.options);
}

再在Tree函数返回值中增加一个属性:

setData: $.proxy(this.setData, this)

这样,便给 bootstrap-treeview 的 Tree 增加了一个新方法,其实很简单。

AngularJS directive指令适配代码实现

有了对bootstrap-treeview基本的用法了解,现在就可以写我们适配的指令了。这里,我们实现一个适配如下树形结构的数据源,多级代理商结构:

[{
    "id": 1,
    "name": "一级代理商",
    "agents": [{
        "id": 2,
        "name": "二级代理商",
        "agents": [{
            "id": 5,
            "name": "三级代理商"
        }]
    }]
}, {
    "id": 3,
    "name": "二级代理商",
    "agents": [{
            "id": 4,
            "name": "三级代理商"
        }, {
            "id": 6,
            "name": "三级代理商"
        },
        {
            "id": 7,
            "name": "终端代理商"
        }
    ]
}]

代理商数据源中并没有href属性,可以在我们适配的过程中,动态生成。

主模块 app.moduel.js

定义一个模块 app

define([
    'require',
    'angular'
], function(require, angular) {
    'use strict';
    return angular.module('app', []);
});

定义指令 treeview.directive.js

define([
    'require',
    'app.module'
], function(require, app) {
    'use strict';

    app.directive('treeView', TreeView);

    function TreeView() {
        return {
            template: '
', scope: { items: '=', // 节点数据源,可以是自己的原始数据结构,有 adpater 函数进行适配 adapter: '&' // 适配函数,这是实现适配的关键 }, replace: true, link: linkFn }; } // 链接函数 function linkFn(scope, element, attrs) { // 从scope当中取出已经被 AngularJS 帮我们解析过的适配函数 // 注意不是 scope.adapter,因为经过AngularJS解析过后, // scope的adapter属性只是,我们真正传入的函数表达式的一个代理, // 通过这个代理函数的调用,才能得到真正的函数本身 var adapterFn = scope.adapter(); // 创建树 element.treeview({ enableLinks: true, showTags: true, data: [] }); // 用于缓存数据源,数据未变化,不要去渲染 var cachedItems = []; // 监听 items 属性的变化,如果变化了,就将数据源更新到 bootstrap-treeview 中 scope.$watch('items', function(items) { // 如果数据源为变化,直接返回 if (angular.equals(cachedItems, items)) return; // 缓存变化数据 cachedItems = items; // 存放适配之后的数据源 var nodes = []; // 将数据源中的数据,逐条进行适配 angular.forEach(items, function(item) { // 调用外部适配函数,将适配只收的节点存放近 nodes 数组中 adapterFn.call(scope, nodes, item); }); // bootstrap-treeview 本身没有提供 setData 函数,为能够动态设置数据源,我加入的 element.treeview(true).setData(nodes); }); } // 这里无意义,因为 requirejs 要求 define 函数返回一个对象,也可以不返回 return {}; });

定义控制器 agents.controller.js

define([
    'require',
    'app.module',
    'treeview'
], function(require, app) {
    'use strict';

    app.controller('AgentCtrl', ['$scope', '$http', AgentCtrl]);

    function AgentCtrl($scope, $http) {
        $scope.list = list;
        $scope.agentAdapter = agentAdapter;

        // 查询代理商
        // list();

        function list() {
            $http.get('/raws/agents.json').then(function(response) {
                var _root = {
                    id: 0,
                    name: '根节点',
                    agents: response.data
                };

                var agents = [_root];
                $scope.agents = agents;
            }, function(err) {
                console.error(err);
            })
        }

        // 多级代理商适配函数
        function agentAdapter(nodes, agent) {
            var node = {};
            node.text = agent.name;
            // 根据代理商的属性,动态生成 href 属性
            // 如果是根节点,不能点击
            if (agent.id === 0) {
                node.href = 'javascript:void(0);';
            } else {
                node.href = '/agents/' + agent.id + '.json';
            }

            nodes.push(node);

            if (agent.agents && agent.agents.length > 0) {
                node.tags = [agent.agents.length];
                // 生成子节点
                node.nodes = [];

                // 遍历下级代理商适配子节点
                angular.forEach(agent.agents, function(agent) {
                    agentAdapter(node.nodes, agent);
                });
            }
        }
    }

    return {};
});

页面 index.html





    
    
    
    TreeView Directive Demo

    

    
    

    



    

运行截图

  1. 初始页面
页面初始状态
  1. 点击Refresh
AnguarJS directive调用外部函数_第3张图片
加载数据源之后

项目完整代码

http://git.oschina.net/dzhang/treeview

你可能感兴趣的:(AnguarJS directive调用外部函数)