avalon2已经稳定下来,是时候教你们如何使用组件这个高级功能了。javascript
组件是咱们实现叠积木开发的关键。css
avalon2实现一个组件很是轻松,而且如何操做这个组件也比之前的avalon2,仍是react, angular轻松多了,不须要flux这样奇怪的额外设施。html
avalon2的组件包含三部分,以经典的行为结构样式相分离。一般咱们命名为index.js, template.html, style.scss。前端
好比咱们开发一个弹出层组件(有遮罩的那种),其目录结构就是以下。vue
modal ----|index.js ----|template.html ----|style.scss
index.js是使用nodejs的模块机制,不过经过webpack,咱们能够对require进来的文件进行预处理。所以咱们要事先搞定webpack及其一些经常使用loader。其实也很少,就是css-loader, text-loader, style-loader, sass-loader。而sass-loader要依赖node-sass这个巨可怕的模块,它要依赖更多东西,这对你的网速与耐性有必定要求。为了让你尽快搞定这些依赖,建议你设置一下npm 的代理,如使用cnpm。java
npm配置镜像、设置代理node
前端之Sass/Scss实战笔记react
安装webpack时最好指定版本,使用1.13.1,2.*并不稳定。咱们整个应用都使用webpack打包。webpack
咱们创建一个ms-modal的文件夹。而后在命令行底下,使用npm init命令来初始化仓库吧,一路回车,最后敲上你的大名:git
而后修改package.json文件,添加devDependencies这个键值对,最后变成这样
{ "name": "ms-modal", "version": "1.0.0", "description": "modal", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { "type": "git", "url": "git+https://github.com/RubyLouvre/ms-modal.git" }, "dependencies": { "avalon2": "~2.1.1", "url-loader": "0.5.7", "node-sass": "^3.8.0", "sass-loader": "^3.2.2", "style-loader": "~0.13.1", "css-loader": "~0.8.0", "text-loader": "0.0.1", "webpack": "^1.13.1" }, "author": "RubyLouvre", "license": "MIT", "bugs": { "url": "https://github.com/RubyLouvre/ms-modal/issues" }, "homepage": "https://github.com/RubyLouvre/ms-modal#readme" }
各个模块的做用
而后npm install
为了美观,咱们用到了iconfont,这个我已经为大家准备好了。
创建一个子目录放 iconfont字体。
而后创建一个font.scss,内容省去,不是咱们学习的重点。
创建一个btn.scss子模块,内容省去,不是咱们学习的重点。
再创建一个style.scss模块,它引入btn.scss, font.scss,内容以下:
@import "./font.scss"; @import "./btn.scss"; .modal-mask{ position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(55,55,55,.6); z-index: 100; display: flex; align-items: center; justify-content: center; } .confirm-content{ padding-left: 30px; padding-top: 30px; padding-bottom: 30px; } .modal-confirm{ width: 400px; box-sizing: border-box; padding: 30px 40px; background-color: #fff; border-radius: 6px; transition: transform .3s ease; i{ color: #fa0; font-size: 24px; position: relative; top: 2px; } .confirm-btns{ text-align: right; } } .modal-box{ width: 520px; box-sizing: border-box; background-color: #fff; border-radius: 6px; } @media only screen and (max-width: 640px) { .modal-confirm{ width: 100%; margin: 0 20px; padding: 10px 20px; } .modal-box{ width: 100%; margin: 0 20px; } } .modal-header{ padding: 13px 18px 14px 16px; border-bottom: 1px solid #e9e9e9; position: relative; i{ position: absolute; right: 20px; top: 15px; font-size: 14px; cursor: pointer; } h3{ font-size: 14px; } } .modal-body{ padding: 16px; } .modal-footer{ padding: 10px 18px 10px 10px; border-top: 1px solid #e9e9e9; background: #fff; border-radius: 0 0 6px 6px; text-align: right; } .modal-enter { opacity: 0; } .modal-enter-active{ opacity: 1; .modal-confirm{ transform: scale(1.1); } .modal-box{ transform: scale(1.1); } } .modal-leave { opacity: 1; } .modal-leave-active{ opacity: 0; .modal-confirm{ transform: scale(1.1); } .modal-box{ transform: scale(1.1); } } .modal-enter,.modal-leave { transition: all .3s ease; }
注意: scss文件中不能出现 中文,不然会编译失败
这里用到了动画效果,使用modal-enter, modal-leave, modal-enter-active, modal-leave-active等类名实现,原理与angular是一致的。能够到这里温习一下。
再创建一个template.html.之因此不学vue, polymer将组件全部东西并成一个文件,是由于对于普通的html文件,全部IDE或文本编辑器都有自带的语法高亮。而且里面须要什么处理,能够直接在webpack中配置。
template.html的内容以下:
<div class="modal-mask" ms-visible="@isShow" ms-effect="{is:'modal'}"> <div class="modal-box"> <div class="modal-header"> <h3>{{@title}}</h3> <i class="iconfont icon-cross" ms-click="@cbProxy(false)"></i> </div> <div class="modal-body"> <slot name="content"></slot> </div> <div class="modal-footer"> <button class="btn" ms-click="@cbProxy(false)">取 消</button> <button class="btn btn-primary" ms-click="@cbProxy(true)">确 定</button> </div> </div> </div>
须要说明一下modal组件通常要直接放在body底下,是其直接子元素,方便其蒙板能罩住整个页面。上面的.modal-mask
就是蒙板,.model-box
就是弹出层,弹出层里面又分三大部分,标题栏,内容区与底部的按钮区。内容区好比复杂,咱们使用DOM插入点机制来设置,换言之,那里使用slot元素占位。之后咱们直接在自定义标签里面添加对应标签,它就会挪到slot的位置上了!
modal组件通常有以下属性:
而后是组件自己index.js
到目前为止,咱们的目录以下:
index.js主要是引用模板与样式与avalon2主库,而后代码主体为avalon.component这个方法的使用。
var avalon = require('avalon2') require('./style.scss') avalon.component('ms-modal', { template: require('text!./template.html'), defaults: { title:'modal', isShow: true, cbProxy: function(ok){ } }, soleSlot: 'content' })
defaults对象里面定义组件要用到的属性,soleSlot是占位元素slot的名字。
关键是dbProxy的实现,咱们要求点击上面的叉叉与下面的取消按钮时调用onCanel回调,若是这个回调什么都不返回,就直接隐藏弹层。若是onCancel是返回false或是返回一个相似Promise的对象(带next方法),就不会隐藏弹层。 点击其确认按钮,则是调用onOk回调,其余逻辑与onCancel类似!
cbProxy: function (ok) { var cbName = ok ? 'onConfirm' : 'onClose' if (this.hasOwnProperty(cbName)) { var ret = this[cbName]() if (ret !== false || (ret && typeof ret.next === 'function')) { this.isShow = false } } else { this.isShow = false } }
而后我在组件onReady钩子处理一些样式问题,好比说你要盖住整个窗口,若是不想拉大整个蒙板,那么最好就是将body的overflow:hidden。 此外还要阻止第一次动画效果。
onReady: function(){ var el = this.$element el.style.display = 'none'//强制阻止动画发生 this.$watch('isShow', function(a){ if(a){ document.body.style.overflow = 'hidden' }else{ document.body.style.overflow = '' } }) }
到此为止,咱们的组件已经写好了,是否是快得不可思议。
而后咱们创建一个main.js入口文件,它里面调用modal组件或引入其余业务代码,为简单起见,咱们如今只是定义了一个页面vm。
var avalon = require('avalon2') require('./index') avalon.define({ $id: 'test', show: function(){ this.config.isShow = true }, config: { isShow: false, onCancel: function(){ alert('cancel') }, onOk: function(){ alert('ok') }, title:'这是测试' } }) module.exports = avalon
注意,最后必须返回avalon,用于webpack.cofig的 output配置
固然之后改一下webpack.config,可能就不须要这样写。有关如何利用webpack 进行工程化,我也在不断探索。你们有好的方案能够留言给我。
咱们再看一下如何打包。建议一个webpack.config.js,内容以下:
var webpack = require('webpack'); var path = require('path'); function heredoc(fn) { return fn.toString().replace(/^[^\/]+\/\*!?\s?/, ''). replace(/\*\/[^\/]+$/, '').trim().replace(/>\s*</g, '><') } var api = heredoc(function () { /* avalon的弹出层组件 1. isShow: 用于控制显示与否 2. title: 标题 3. content: 内容,这个是一个很是复杂的HTML结构 4. onOk 5: onCancel 使用 兼容IE6-8 <xmp ms-widget="[{is:'ms-modal'}, @config]"> <p>弹窗的内容</p> <p>弹窗的内容</p> <p>弹窗的内容结束!</p> </xmp> 只支持现代浏览器(IE9+) <ms-modal ms-widget="@config"> <p>弹窗的内容</p> <p>弹窗的内容</p> <p>弹窗的内容结束!</p> </ms-modal> */ }) module.exports = { entry: { index: './main' }, output: { path: path.join(__dirname, 'dist'), filename: '[name].js', libraryTarget: 'umd', library: 'avalon' }, //页面引用的文件 plugins: [ new webpack.BannerPlugin('弹出层组件 by 司徒正美\n' + api) ], module: { loaders: [ //ExtractTextPlugin.extract('style-loader', 'css-loader','sass-loader') //http://react-china.org/t/webpack-extracttextplugin-autoprefixer/1922/4 //http://stackoverflow.com/questions/34639720/webpack-font-include-issue // https://github.com/b82/webpack-basic-starter/blob/master/webpack.config.js {test: /\.scss$/, loader:'style!css!sass',exclude: /node_modules/}, {test: /\.(ttf|eot|svg|woff2?)((\?|#)[^\'\"]+)?$/, loader: 'url-loader'} ] }, resolve: { extensions: ['.js', '', '.css'] } }
咱们执行webpack命令,它就合并成一个文件,放在dist目录下,但有时你死活装不上node-sass什么,搞不定SASS的编译,也没问题,能够koala编译好,直接在index.js中引用纯CSS文件。
最后创建一个page.html文件,欣赏一下咱们的劳动成果:
<!DOCTYPE html> <html> <head> <title>modal</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <script src="./dist/index.js"></script> </head> <body ms-controller="test"> <xmp ms-widget="[{is:'ms-modal'}, @config]"> <p>弹窗的内容</p> <p>弹窗的内容</p> <p>弹窗的内容结束!</p> </xmp> <p><button ms-click="@show">显示弹出</button></p> </body> </html>
你们能够到这里下载到此工程
其余参考资料: