摘要:線上另加入了排行榜功能,如需查看源碼的,請切換到分支整個項目結構清晰,尤其單文件組件的表現力尤為突出,使得每個組件的邏輯都沒有過于復雜,而且在的統籌下,的單向數據流模式使得所有的變化都在可控制可預期的范圍內。
2016注定不是個平凡年,無論是中秋節問世的angular2,還是全面走向穩定的React,都免不了面對另一個競爭對手vue2。喜歡vue在設計思路上的“先進性”(原諒我用了這么一個詞),敬佩作者尤小右本人的“國際范兒”,使得各框架之間的競爭略顯妖嬈(雖然從已存在問題的解決方案上看,各框架都有部分相似之處)。
因為vue2已經正式release,本教程做了一些修改(針對vue2)
所謂設計上的先進性,以下幾點是我比較喜歡的:
數據驅動的響應式編程體驗不同于AngularJS里基于digest cycle的臟檢查機制,執行效率更高。內部基于Object.defineProperty特性做漂亮的hack實現(而且不支持IE8,大快人心)。更多細節,看這里
因為這個機制的出現,我們再也也不需要顧慮雙向綁定的效率問題;亦或是像React那樣搞什么immutability(對這塊感興趣可以看(譯)JavaScript中的不可變性),因為Object.definePropery洞悉你的一切,媽媽再也不用擔心你忘記實現shouldComponentUpdate了.
到這里你可能還不能體會vue的精妙,是時候來個栗子了!
假設我們有一個字段fullName,它依賴其他字段的變化,在AngularJS里,我們或許會用命令式這樣寫道:
$scope.user = { firstName: "", lastName: "" } $scope.fullName = "" //告訴程序主動“監視”user的變化,然后修改fullName的值 $scope.$watch("user", function(user) { $scope.fullName = user.firstName + " " + user.lastName }, true)
若是vue,改用聲明式,寫法如何?
data() { return { firstName: "", lastName: "" } }, computed: { fullName() { // 生命一個fullName的計算屬性,并告訴程序它是由firstName和lastName組成。 // 至于具體是什么時候/如何完成數據拼裝的,你就不用管了 return this.firstName + " " + this.lastName } }
相對于AngularJS里命令式的告訴框架,fullName一定要監視user對象的變化(注意里面還是deepWatch,效率更差),并且隨之改變;vue以數據驅動為本質,聲明式的定義fullName就是由firstName和lastName組成,無論怎么變化,都是如此。這種寫法,更優雅有沒有?
如果有興趣看看用angular2如何實現相同的小游戲,走這里單文件組件模式
還在為一堆代碼文件,到底哪個是JavaScript邏輯部分、哪個是css/less/sass樣式部分、哪個是html/template模板部分;他們又該如何組織,怎么“編譯”、如何發布?
有了單文件組件范式,配合webpack4(雖然文檔依舊WIP),組件自包含,完美、沒毛病!還有強大的開發工具支持,看著都賞心悅目,來個效果圖:
用了這么多版面,說了一些好處,那么當我們真正需要面對一個應用,需要上規模開發時,vue又能帶來怎樣的變化呢?憋了幾天,我想今天就寫一個小游戲來試試整體感覺,先來看看我們今天的目標:
完整源碼在這里:vue-memory-game
看了效果,知道源碼在哪里了,那我們繼續?
組件分解Break the UI into a component hierarchy,相信寫過React的朋友對這句話都不陌生,在使用一種基于組件開發的模式時,最先考慮,而且也尤為重要的一件事,就是組件分解。下面我們看看組件分解示意圖:
我們根據分解圖,先把未來要實現的組件挨個兒列出來:
Game, 最外層的游戲面板
Dashboard, 上面的logo,游戲進度,最佳戰績的容器
Logo,左上角的logo
MatchInfo, 正中上方的游戲進度組件
Score, 右上角的最佳戰績組件
Chessboard, 正中大棋盤
Card, 中間那十六個棋牌
PlayStatus, 最下方的游戲狀態信息欄
帶薪搭環境(又來了?^^)#創建目錄 mkdir vue-memory-game #創建一個package.json npm init #進入目錄 cd vue-memory-game #安裝開發環境依賴 npm install --save-dev babel-core babel-loader babel-plugin-transform-object-rest-spread babel-plugin-transform-runtime babel-preset-env css-loader file-loader html-webpack-plugin style-loader vue-hot-reload-api vue-html-loader vue-loader vue-style-loader vue-template-compiler webpack webpack-cli webpack-dev-server webpack-merge #安裝運行時依賴 npm install vue vuex
這里開發環境依賴內容有點多,但不要害怕,大部分時候你不太關心里面的東西(當然,如果你要進階,你要升職、加薪、迎娶白富美,那你最好搞清楚他們每一項都是什么東西)
另外在運行時依賴里不僅看到了vue,還看到了vuex。這又是個什么鬼?先不要慌,也別急著罵娘,我們來考慮一個問題,試想下,整個游戲按照上面分解的組件開發時,各個組件之間想必在邏輯上多少是有關系的,譬如:Card在Chessboard中的翻牌、配對,當然會影響到上方的Dashboard和下面的PlayStatus。那么“通信”,就成了待解決問題。
以前我們試圖用事件廣播來做,但隨之而來的問題是,在應用不斷的擴展、變化中,事件變得越來越復雜,越來越不可預料,以至于越來越難調試,越來越難追蹤錯誤的root cause。這當然不是我們想要的,我們希望應用的各個部分都易維護、可擴展、好調試、能預測。
于是一種叫單向數據流的方式就冒了出來,用過React的人想必也不陌生,各組件的間的數據走向永遠是單向、可預期的:
這當然也不是facebook的專利,都說vue牛逼了,那一定也有一個單向數據流的實現,就是我們這里用到的vuex。
掌握目錄結構vue-memory-game ├── css │?? └── main.css ├── img │?? ├── ... │?? └── zeppelin.png ├── js │?? ├── components │?? │?? ├── card │?? │?? │?? ├── Card.vue │?? │?? │?? └── Chessboard.vue │?? │?? ├── dashboard │?? │?? │?? ├── Dashboard.vue │?? │?? │?? ├── Logo.vue │?? │?? │?? ├── MatchInfo.vue │?? │?? │?? └── Score.vue │?? │?? ├── footer │?? │?? │ └── PlayStatus.vue │?? │?? │ │?? │?? └── Game.vue │?? │ │?? ├── vuex │?? │ ├── actions │?? │ │?? └── index.js │?? │ ├── getters │?? │ │?? └── index.js │?? │ ├── mutations │?? │ │?? └── index.js │?? │ └── store │?? │ ├── index.js │?? │ └── statusEnum.js │?? │ │?? └── index.js │ ├── index.html_vm ├── package.json ├── webpack.config.js └── webpack.config.prod.js配置webpack
看了上面的文件目錄結構圖,要配置webpack,已經沒有難度了,直接上代碼:
const { resolve, join } = require("path") const HtmlWebpackPlugin = require("html-webpack-plugin") module.exports = { mode: "development", entry: { index: "./js/index.js" }, output: { filename: "[name].[hash].bundle.js", path: resolve(__dirname, "build") }, devtool: "#source-map", devServer: { contentBase: join(__dirname, "build"), compress: false, port: 8080, host: "0.0.0.0", hot: true, inline: true }, module: { rules: [ { test: /.vue$/, use: [ { loader: "vue-loader" } ], exclude: /node_modules/ }, { test: /.js$/, use: ["babel-loader"], exclude: /node_modules/ }, { test: /.css$/, use: ["style-loader", "css-loader"] }, { test: /.(png)$/, use: ["file-loader"] } ] }, resolve: { extensions: [".js", ".vue"] }, plugins: [ new HtmlWebpackPlugin({ filename: "index.html", inject: "body", template: "index.html_vm", favicon: "img/favicon.ico", hash: false }) ] }
我在這兒沒有過多的涉及webpack的基本使用,反正webpack4的文檔還在進行中,翻源碼去吧(~逃)這里我們用了html-webpack-plugin里自動將編譯后的bundle注入index.html_vm里,并生成最終的html。所以index.html_vm作為模板,我們也要先寫出來:
touch index.html_vm
再將如下內容填入其中:
編寫應用入口vue-memory-game
在webpack.config.js里,我們看到了
entry: { index: "./js/index.js" }
這也是本章整個vue應用的入口:
// 引入一些初始化的簡單樣式 import "../css/main.css" // 引入vue庫 import Vue from "vue" // 引入本游戲核心入口組件 import Game from "./components/Game" // 引入狀態管理機 import store from "./vuex/store" /* eslint-disable no-new */ new Vue({ el: "#application", render(h) { return h(Game) }, store })
本章代碼本采用ES2015語法編寫,譬如:components: {Game},相當于components: {Game: Game},這是enhanced-object-literals全局初始化樣式我在這里沒有過多介紹vue2的基本使用,不過我盡量列出可能涉及的知識點,便于學習
上面js/index.js里第一行就引用了全局初始化樣式的css/main.css,我們就先把它寫了吧:
* { box-sizing: border-box; padding: 0; margin: 0; } html, body { width: 100%; height: 100%; } body { display: flex; justify-content: center; align-items: center; }
本章大量使用flexbox來布局排版,不了解的可以學習一下(雖然我也是半吊子)
這段css/main.css之所以能被加載成功,多虧了webpack.config.js中的這段配置:
{ test: /.css$/, use: ["style-loader", "css-loader"] },
得利于css-loader和style-loader,上述css可以成功從index.js文件里引入,并被webpack處理到dom的標簽里
第一個組件Game剛才的入口js/index.js里,我們注入了游戲主界面組件js/components/Game,下面就來創建它吧:
TBD...
單文件組件的魅力,到這里終于可以瞄一眼了,第一部分是模板,第二部分是邏輯,第三部分是樣式。
這里上還有個scoped屬性,表示樣式僅對當前組件以及其子組件的模板部分生效。
單文件組件的加載由webpack.config.js中的配置:
{ test: /.vue$/, use: [ { loader: "vue-loader" } ], exclude: /node_modules/ },
所以我們可以在.vue文件中使用ES2015語法進行開發。
寫了這么多,不運行一下,都說不過去了,現在請打開package.json文件,為其添加如下代碼:
"scripts": { "start": "webpack-dev-server --hot --inline --host 0.0.0.0 --port 8080" }
然后在項目根目錄調用:
#啟動調試 npm start
瀏覽器訪問:http://localhost:8080/,可以看到如下效果:
注意js/components/Game里的兩個"TBD"部分,我們現在來補齊:
這里vuex/actions/index.js和vuex/store/statusEnum.js,我就不分別在這里寫源碼了,內容很簡單,官網基本教程讀完理解無障礙。
因為功能比較簡單,大部分組件僅樣式有差別,為了節省時間,我只挑一個最具代表性的components/card/Chessboard.vue來講講
components/card/Chessboard.vue寫在最后,整體寫完的效果,可以在這里把玩。
線上demo另加入了排行榜功能,如需查看源碼的,請git checkout stage-1切換到stage-1分支
整個項目結構清晰,尤其單文件組件的表現力尤為突出,使得每個組件的邏輯都沒有過于復雜,而且在vuex的統籌下,action -> mutation -> state的單向數據流模式使得所有的變化都在可控制、可預期的范圍內。這點非常利于大型、復雜應用的開發。
另,vue2已經問世,對于之前跟著一起操作過vue版的朋友,發現源碼里有疑惑的變更,請參考升級指南。
vue作為一個僅7000多行的輕量級框架而言,無論生態系統、社區、工具的發展都非常均衡、成熟,完全可以適應多業務場景以及穩定性需求。而且,vue2中對服務器端渲染的支持(而且是前所未有的流式支持),使得你不必再為單頁應用的SEO問題、首屏渲染加速問題而擔憂。欲知詳情,看SSR
總的來說,2016年,vue讓你的編程生涯,又多了一絲情懷(原諒我實在找不到什么好詞兒了)。
如果關于代碼有疑問,歡迎issue,也歡迎start
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/79498.html
摘要:業界著名的開發框架,完美的設計以及組件化開發思想保證了框架的擴展性。面向生產環境的異步網絡通信引擎。使開發人員可以編寫高性能的異步并發,服務。通過簡單的幾行代碼即可完成傳統應用到的升級,給應用帶來實打實的性能提升 Yii2:業界著名的開發框架,完美的OOP設計以及組件化開發思想保證了框架的擴展性。Swoole:面向生產環境的 PHP 異步網絡通信引擎。使 PHP 開發人員可以編寫高性能...
摘要:前言大概是我的業務領域比較狹窄的原因我總是會聽說卻很少在實際的開發中應用或者實踐過它今天剛好看到高級程序設計第三版的數據存儲部分說到了這里就對做一個深入訪談希望和我一樣對似曾相識的朋友可以真正的熟悉并學會利用來服務我們的業務定義是服務器為了 前言 大概是我的業務領域比較狹窄的原因,我總是會聽說cookie,卻很少在實際的開發中應用或者實踐過它,今天剛好看到的數據存儲部分,說到了cook...
摘要:中立的云計算服務商優刻得作為參展商受邀出席,將展示在工業互聯網領域的成熟解決方案及先進成果經驗,推動新一代信息技術和工業制造業融合發展。成都一座來了就不想走的城市天府之國、美食之都、休閑之城…當工業的火遇上成都的辣又會擦出怎樣的火花?當下工業互聯網已成為數字經濟發展、產業轉型升級的重要引擎十四五開局之年更是提出:要培育形成具有國際影響力的工業互聯網平臺推進工業互聯網+智能制造產業生態建設以工...
摘要:的網站仍然使用有漏洞庫上周發布了開源社區安全現狀報告,發現隨著開源社區的日漸活躍,開源代碼中包含的安全漏洞以及影響的范圍也在不斷擴大。與應用安全是流行的服務端框架,本文即是介紹如何使用以及其他的框架來增強應用的安全性。 showImg(https://segmentfault.com/img/remote/1460000012181337?w=1240&h=826); 前端每周清單專注...
摘要:數據浪潮之間的前端工程師十年來,波瀾壯闊的移動互聯網浪潮促進了技術的迅猛發展,隨著瀏覽器性能網絡帶寬等基礎設施的提升,也能夠承載起包含復雜交互可視化計算邏輯需求的富客戶端應用。 showImg(https://segmentfault.com/img/remote/1460000016874425); 本文是架構師 2018-10 月刊的卷首語,歸納于自筆者的技術之路系列文章,也是對 ...
閱讀 1990·2021-09-22 16:05
閱讀 9255·2021-09-22 15:03
閱讀 2880·2019-08-30 15:53
閱讀 1698·2019-08-29 11:15
閱讀 903·2019-08-26 13:52
閱讀 2348·2019-08-26 11:32
閱讀 1798·2019-08-26 10:38
閱讀 2562·2019-08-23 17:19