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>
你們能夠到這裏下載到此工程
其餘參考資料: