magix,页面区块化利器
什么是区块
其实html标签就是区块,比如 div span a等标签。前端工程师就是在重复使用、组装这些区块(html标签)形成最终的需求页面。这是最原子的区块,我们要达到想要的页面效果,就得不停的重复嵌套这些区块。
但是呢,通常我们所说的区块是这些html标签的组合。比如当我们开发一个页面时,通常都是由多个逻辑关联不强的区块组成的,如常见的页头、页尾、内容区。这些区块通常是由多个html标签组合而成的。
我们可以借签html标签的这种嵌套及DOM Tree思路的,开发一套用于组合嵌套这种大区块的框架。我们把一个复杂的页面拆分成n个区块来开发,再由框架来便利的组合它们。这就是接下来要介绍的magix做的事情
定义区块
在这里我们把区块定义为由一段html标签组成的代码片断,区块最小是一个标签,如<button>。区块可以像html标签一样嵌套,即一个区块可以由多个子区块组成
项目中的区块
当我们在开发一个项目时,如前面提到的页头、页尾、内容区等,这些在我们项目里就是一个个区块,当然像内容区我们仍然可以再拆分子区块。像页头、页尾在项目里可以理解为原子区块,没必要再拆分了。这些区块应该很容易被复用。
准备工作
magix适配了不同的加载器与dom操作类库,有amd、cmd及kissy,可点击这里查看,当然您也可以自己定制,定制方法点击这里
接下来我们使用cmd版本,即seajs+jq来讲解magix的区块化管理
安装
新建一个magix-test目录,在magix-test目录里放上package.json文件如下:
{
"name": "magix-test",
"version": "1.0.0",
"description": "magix示例项目",
"keywords": [
"magix",
"view"
],
"dependencies": {
"jquery": "",
"seajs": "",
"magix": ""
},
"author": "xinglie <[email protected]>",
"license": "MIT"
}
然后通过npm install把seajs、jquery及magix安装到本机
页面开发
新建index.html如下
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Magix-test</title>
<script src="node_modules/seajs/dist/sea-debug.js"></script>
<script src="node_modules/jquery/dist/jquery.js"></script>
</head>
<body >
<div id="header"></div>
<div id="footer"></div>
<script type="text/javascript">
seajs.config({
debug:true,
alias:{
magix:location.href+'./node_modules/magix/dist/cmd/magix-debug'
},
paths:{
views:'./views'//等下我们新建的区块都放到views目录下
}
});
define('$',function(){//shim magix内部在依赖jquery或zepto时,使用的是$符号,即magix并未指定具体的类库。外部需要提供$这个模块,这样可以很方便的在jq或zepto及其它类库中切换
return jQuery;
});
</script>
</body>
</html>
这样我们的首页就完成了,接下来我们开发header及footer,然后把它们渲染到index.html里相应的位置上。
我们在magix-test目录下新建views目录,我们把新建的header及footer放到该目录里 header.js如下
define('views/header', ['magix'], function(require) {
var Magix = require('magix');
return Magix.View.extend({
render: function() {
var html = 'I am header';
this.setHTML(this.id, html);
}
});
});
新建footer.js,代码如header 然后我们修改index.html,加载header及footer,修改后的index.html如下
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Magix-test</title>
<script src="node_modules/seajs/dist/sea-debug.js"></script>
<script src="node_modules/jquery/dist/jquery.js"></script>
</head>
<body >
<div id="header" mx-view="views/header"></div>
<div id="footer" mx-view="views/footer"></div>
<script type="text/javascript">
seajs.config({
debug:true,
alias:{
magix:location.href+'./node_modules/magix/dist/cmd/magix-debug'
},
paths:{
views:'./views'//等下我们新建的区块都放到views目录下
}
});
define('$',function(){//shim
return jQuery;
});
seajs.use('magix',function(Magix){
Magix.boot();//处理页面上的mx-view节点
});
</script>
</body>
</html>
然后在web server中查看index.html即可,如果没什么问题应该就能看到header及footer已经渲染到了相应的节点里
事件处理
我们增加一个登录按钮,及点击按钮处理登录相关的事情。事件这块你可以用jquery的事件方法在render中自己绑定,也可以使用magix定义的方法书写事件,推荐使用magix定义的方法来处理事件:高性能,自动解绑
我们修改header.js如下
define('views/header', ['magix'], function(require) {
var Magix = require('magix');
return Magix.View.extend({
tmpl:'I am header <div><button mx-click="processLogin()">Login</button></div>',
render: function() {
this.setHTML(this.id, this.tmpl);
},
'processLogin<click>':function(e){
console.log(e);
alert('Login');
}
});
});
这样就完成了事件的绑定与处理。注意绑定在button标签上的mx-click="processLogin()",事件采用mx-type的形式,不能是onclick。接收处理写成processLogin<click>,表明processLogin只处理click事件,如果button标签上你写成了mx-mousedown="processLogin()",那么下面的回调将不会执行哦
magix内部也是对接的jquery的事件处理函数,并非自己另外写了一套事件处理,只是在这个过程中magix有优化,所以推荐使用magix的写法。
区块嵌套
实际开发中区块会非常复杂,我们通常把一个复杂的区块再拆分子区块,然后再组装起来。我们这里假设header非常复杂,比如我们新建一个header-login区块用于单独处理登录的事情。
header-login代码如下
define('views/header-login', ['magix'], function(require) {
var Magix = require('magix');
return Magix.View.extend({
tmpl: '<button mx-click="processLogin()">Login</button>',
render: function() {
this.setHTML(this.id, this.tmpl);
},
'processLogin<click>':function(e){
console.log(e);
alert('Login');
}
});
});
既然login已经单独成区块了,我们修改header.js,直接引用views/header-login区块
define('views/header', ['magix'], function(require) {
var Magix = require('magix');
return Magix.View.extend({
tmpl: 'I am header <div mx-view="views/header-login"></div>',
render: function() {
this.setHTML(this.id, this.tmpl);
}
});
});
我们只需要在header.js中通过mx-view标签属性引用另外一个区块即可。这样就完成了子区块的拆分及组装功能。 刷新index.html我们可以看到和之前没拆分时是一样的
区块可视化
我们这样组装出来的页面,看上去和普通页面是一样的,但是我们如何快速知道页面上被拆分了哪些区块,及区块间的关系呢?这时候需要magix的配套工具magix-inspector
这是一个js文件,我们可以通过引入线上链接或npm包,更多引入方式可以查看https://github.com/thx/magix-inspector
我们修改index.html,引入线上链接 在index.html的head中增加如下script标签
<script src="//thx.github.io/magix-inspector/index.js"></script>
刷新index.html就可以看到右上角有一个区块间关系图,鼠标指向各个区块会高亮当前区块的范围及区块的路径地址等信息
调试工具展示的结构如图:
可视化工具所展示的区块间关系其实和DOM Tree是非常一致的
区块化的好处
我们可以把一个复杂的页面拆分成n个独立的区块单独维护与处理,方便多人同时开发,同时当一个区块复杂时,我们仍然可以快速的把它进行拆分,然后再组装回来,避免出现一个庞大的js文件。 这种区块可以通过mx-view标签属性被引用在项目中的任何地方,当一个区块被复用在多个地方时非常方便,比如这时候你可以在index.html里再添加上一个<div mx-view="views/header-login"></div>则页面上就会再出现登录按钮,多个同时存在的同一个view之间互相独立不冲突
后续
magix核心功能压缩后仅6kb,gzip后只有3kb,非常小,但功能非常强大,今天介绍的仅仅是冰山一角。 阿里妈妈所有后台产品及营销页面均是用magix开发,这里放几个链接 阿里妈妈帮助中心 afp 智钻
magix的项目地址在这里https://github.com/thx/magix 欢迎试用~
如果你不想按上述教程自己建文件,我把上述示例中的代码放到了附件里,可以点击链接下载
链接是淘云盘的,链接为 http://yunpan.taobao.com/s/2lRwLK22mnX 提取码为:73bzKa
其实页面区块化这个思路很早就有了,比如iframe这个标签,我们可以开发一个通用页面,然后在同一个页面上可以用iframe来嵌套显示这个通用页面,并且在url中传递参数,如下
<iframe src="list.html?type=1"></iframe>
<iframe src="list.html?type=2"></iframe>
当然,iframe有它的好处和问题,不过这种思路确实不错。
再比如asp.net,它的组件功能也是这样区块化的。比如<asp:Login>,组件也是可以嵌套形成更大的组件最终组装成页面。
类似这样的思路在服务端还是比较多的,发展到现在前后端分离的时候,magix致力于解决前端的这种嵌套与复用,思路都是类似的。如果你理解这些则上手magix会快速一些
Hi,不知道是不是代码更新(Magix 3.2.3)的缘故,上面的代码已经跑不通了~经过尝试,有一些地方需要修改。
- 在
index.html中,原来对于magix路径的设置方式会获取失败,修改如下:
seajs.config({
debug: true,
alias: {
//此处路径进行调整
magix: location.href + '/../node_modules/magix/dist/cmd/magix-debug'
},
paths: {
views: './views'
}
});
- 在
header.js文件中,通过var html = 'I am header <div><button mx-click="processLogin()">Login</button></div>';设置的绑定点击事件被触发时会报错,进行如下修改得以解决:
define('views/header', ['magix'], function (require) {
var Magix = require('magix');
return Magix.View.extend({
tmpl:'i am header <button mx-click="processLogin()">Login</button>',
render: function () {
this.setHTML(this.id, this.tmpl);
},
'processLogin<click>': function (e) {
console.log(e);
alert('Login');
}
});
});
@bigfengyu 非常感谢反馈,这个说明里确实用新版本有点问题,路径引用问题我已修改。 另外事件那块我暂不确定这样改了之后是否就正常了,模板这块推荐使用magix-combine工具进行打包到js中,http://thx.github.io/magix/#!/tutorial?s=intro 这里有完善的教程。
@xinglie 今早又看了一下,路径引用问题是这样的:
您访问的可能是 localhost:8080/ 而我访问的是 localhost:8080/index.html,所以导致引用不正确,为了保证通用性,可以写成 location.origin + '/node_modules/magix/dist/cmd/magix-debug'。
@bigfengyu 感谢提醒,我回头把教程之类的再认真过一遍,减少这样的问题发生。你在使用时,有任何问题都欢迎留言交流哦。
找到了一个文档中的 typo~
地址:
https://thx.github.io/magix/#!/guide?s=view-ehandling
位置:
我们可以调用e.stopPropagation()来阻止冒泡,如下
// app/views/index.js var Magix = require('magix'); module.exports = Magix.View.extend({ render:function(){ this.setHTML(this.id,'app/views/index rendered'); }, 'outer<click>':function(e){ console.log('outer clicked'); }, 'inner<click>':function(e){ console.log('inner clicked'); e.stiopPropagation(); // typo } });
@bigfengyu 非常感谢,下周就处理
您好,我尝试使用 gulp doc 命令构建 doc 失败,可能是前些时候对于 ./tool/gulpfile.js 中 type 变量的改动影响了构建过程。
bogon:tool fengyu$ gulp doc
[17:20:38] Starting 'combine'...
[17:20:38] Finished 'combine' after 45 ms
[17:20:38] Starting 'doc'...
[17:20:38] 'doc' errored after 239 μs
[17:20:38] Error: ENOENT: no such file or directory, open '../dist/cmd,amd,kissy,webpack/magix-debug.js'
@bigfengyu 我修复了。之前变量type并不是逗号分割的字符串,后来我修改了type但未修改doc,导致不能构建doc,另外构建出来的doc数据并不在magix目录下,而是和magix同级的magix-doc3目录。https://github.com/thx/magix-doc3 你需要把这个克隆到与magix平级的目录下。
你好,我按照教程学习magix时遇到问题. Magix 3.2.0版本
教程内有的例子代码缺少了一些$符号. 在局部刷新的例子代码中
render: function() {
this.$updater.set({
a: 10,
b: 20
}).digest();
}
使用这个引起报错,不知道如何解决,请指教
(index):90 Uncaught TypeError: Cannot read property 'replace' of undefined
at Updater_UpdateDOM (magix-debug.js:2027)
at Updater.digest (magix-debug.js:2162)
at NView.tes
magix 区块化 和 vue 的区块化 有什么 本质的区别吗
@zwjat 请使用cli工具https://github.com/thx/thx-cli 进行新版本的尝试。 同样的问题不同的解法而已,可以尝试体会下