【如何实现backbone组件化开发】 第二篇:优化方案的实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/billll/article/details/79293814

系列文章
【如何实现backbone组件化开发】 第一篇:无组件所带来的问题

在上一篇文章中,我们已经分析了Backbone在组件化开发上的不足,以及如何使用打包手段弥补这些不错。接下来我们来逐步通过一个例子来讲解优化的过程

1. 场景假设

假设我们需要使用Backbone编写这样一个输入框组件,它有一个input和一个label组成。当用户在input中输入文字,并且触发blur事件时,输入的文字会在label中显示。如下图所示。
这里写图片描述

我们还需要一个tab组件,tab组件上有多个tab切换按钮,点击不同的按钮能打开对应的tab页。每个tab页中可以嵌套任意组件,例如嵌套上面的输入框组件。如下图所示。
这里写图片描述

线上Demo
源代码

2. 项目结构

这里写图片描述

项目中包含myInput和tab两个组件。myInput组件中包含5个文件,我们挨个来看。

2.1 tpl.htm

tpl.htm是组件的模板文件,例如underscore模板文件。

2.2 model.js

model.js是Backbone中的Model实例。

2.3 view.js

view.js是Backbone中的view实例,view.js中会引用tpl.htm。

2.4 index.less

组件样式文件

2.5 index.js

组件的入口,组件入口会引入index.less、view.js、model.js。

3. 个文件解析

3.1 tpl.htm

这里的模板包含一个input元素和用于展示数据的value

<h3><%=title%></h3>
<div>
    <strong><%=label%></strong></strong><input class="my-input" type="text" name="firstname" placeholder=<%=placeholder%> />
</div>
<div>
    <strong><%=word%></strong><%=value%>
</div>

3.2 model.js

model文件没有什么特殊。

var model = Backbone.Model.extend({
    defaults: function () {
        return {
            title: "title",
            label: "label",
            placeholder: "placeholder",
            word: "word",
            value: ""
        };
    },
});

3.3 view.js

这里的view.js需要通过underscore-template-loader加载模板文件。通过这个loader实现模板在代码打包阶段的预编译。loader的配置详见第四章。

// 通过underscore-template-loader加载模板文件
var tpl = require("./tpl.htm")

var view = Backbone.View.extend({
    className: 'input-module',
    template: tpl,
    events: {
        // 监听input元素的chang事件,并修改model中的value值。
        'change .my-input': 'valuechange'
    },
    valuechange: function(event) {
        var newValue = event.currentTarget.value;
        this.model.set('value', newValue);
    },
    render: function() {
        this.$el.html(this.template(this.model.attributes));
        if (this.model.get('value') != '') {
            this.$el.find('input').attr('value', this.model.get('value'));
        }
        return this;
    }
});

3.4 index.less

index.less通过less-loader加载到js中,这也就解决了样式文件和组件分离的缺点。

.input-module {
    font-family: 'Microsoft YaHei';
}

strong {
    color: gray;
}

3.5 index.js

index.js通过引入model、view、模板文件、样式文件,把一个组件所有需要的资源整合了起来。并对外提供组件初始化和配置的接口。
所以外部只需要引入组件的入口文件,并进行配置,就可以加载组件的所有资源。这样就做到了组件资源的集中管理。

var model = require("./model"),
    view = require("./view");

require("./index.less");

function myInput() {

}

// 对外初始化接口
myInput.prototype.init = function(title, label, placeholder, word) {
    this._model = new model({
        title: title,
        label: label,
        placeholder: placeholder,
        word: word,
        value: ""
    });

    this._view = new view({
        model: this._model
    });

    this._view.render();
}

// 设置组件标题接口
myInput.prototype.setTitle = function(title) {
    this._model.set('title', title);
}
// 获取Dom
myInput.prototype.getView = function() {
    return this._view;
}

module.exports = myInput;

4 优化过程的解析

4.1 underscore-template-loader

在view.js中我们通过underscore-template-loader实现了在代码打包阶段的模板编译,这项优化可以节省浏览器的编译模板所需要的时间,从而加快模块的加载。

underscore-template-loader源代码

loader的配置

module: {
    loaders: [
      {
        test: /\.htm$/,
        loader: "underscore-template-loader",
        query: {
          // 这个配置可以在最终渲染的模板中加入注释,此处使用模板的文件路径作为注释
          prependFilenameComment: __dirname,
        }
      }
    ]
  }

更详尽的配置可以在github中找到

4.2 less-loader

为了把模块的样式和模块js打包到同一个组件模块中,我们可以使用less-loaderless-loader可以在代码打包阶段把less文件转义为html内联样式,并通过js函数将内联样式插入到页面中。less-loader的配置并不难,可以自行查看文档。这里只贴出基本的配置。

module: {
    loaders: [
      {
        test: /\.less$/,
        use: [
          'style-loader',
          { loader: 'css-loader', options: { importLoaders: 1 } },
          { loader: 'less-loader', options: { strictMath: true, noIeCompat: true } }
          ]
      }
    ]
  }

4.3 整合view与model

当我们引入一个组件时,我们通常希望组件提供一个入口文件,组件的使用者只要引入入口文件就可以调用组件的所有资源。然而一个Backbone组件通常由view和model构成,这使得组件的引用变成头疼的事。

所以我们可以提供一个入口文件,这个入口文件会引入组件所需要的view、model、样式文件等。入口文件对外提供init接口对view和model进行初始化,提供setXXX接口实现对model的修改,提供getView接口返回组件渲染结果。这样我们就可以通过如果文件操作Backbone组件。

Demo请看上一节中的index.js

4.4 组件的嵌套

在Backbone中实现组件嵌套的基本思路是先渲染父组件的Dom,然后将子组件的Dom插入到父组件的节点中。因为每个组件都提供getView接口用于返回组件的Dom,所以父组件可以调用这个接口嵌入任意组件。

我们可以通过父组件的init接口,把子组件的实例对象传入父组件。父组件在构建完自身的Dom后挂在子组件。例如:

tab.prototype.add = function(title, content /* 子组件对象 */, isSelect) {
    var m = new model({
        title: title,
        content: content,
        isSelect: isSelect
    });

    this._collection.add(m);
}

组件嵌套中的另一个关键点是父子组件的通信。先来说父组件如何向子组件传递消息,方案父组件调用子组件的接口,例如子组件上可以提供组件销毁接口,刷新接口等。

而子组件向父组件发送消息则可以通过事件的机制,也就是说子组件的入口需要继承Backbone的Event事件系统,父组件通过监听子组件发出的消息实现通信。

猜你喜欢

转载自blog.csdn.net/billll/article/details/79293814