前端框架Vue.js構(gòu)建大型應(yīng)用淺析
真正的模塊化
前端模塊化很早就開始了,無(wú)論是 require.js,browserify 進(jìn)行模塊化打包, 還是 Angular 進(jìn)行依賴注入,我們都可以把JS代碼分成一個(gè)個(gè)小的模塊并組裝起來(lái)。然后我們還會(huì)通過(guò) less 或者 sass 來(lái)把CSS文件也拆成一個(gè)個(gè)小的模塊來(lái)寫,甚至我們?cè)贑SS代碼中感受到了 封裝,繼承,多態(tài) 等面向?qū)ο蟮奶匦浴?/p>
然而,在 webpack 出來(lái)之前,我們所謂的模塊化根本不能算作模塊化。為什么這么講,因?yàn)槲覀兇嬖谝粋€(gè)重要的問題沒有解決,就是JS模塊對(duì)CSS模塊的依賴。
比如我們有一個(gè)JS模塊 modal 那么我們直接導(dǎo)入并調(diào)用它就能彈出一個(gè)對(duì)話框嗎?如下圖所示可以嗎?
理論上應(yīng)該是這樣的,但實(shí)際上這個(gè) modal其實(shí)還依賴一個(gè)對(duì)應(yīng)的CSS模塊 modal.less ,如果不導(dǎo)入這個(gè)模塊我們是無(wú)法彈出一個(gè)正常的對(duì)話框的,而且,導(dǎo)入這個(gè)CSS模塊竟然不是和導(dǎo)入JS模塊寫在同一個(gè)地方,而是寫在另一個(gè)CSS文件中。也就是說(shuō),其實(shí)依賴關(guān)系是這樣的:
為了使用一個(gè)模塊,我們需要在兩個(gè)文件中分別做一次引入操作。這其實(shí)是一件非常奇怪不合理的事!我們?yōu)槭裁匆K化?就是為了封裝一個(gè)模塊,可以做到導(dǎo)入它就能使用,而它是如何實(shí)現(xiàn)的,它有什么依賴關(guān)系完全是這個(gè)模塊自己處理的,也就是上圖中對(duì) modal.css 的依賴應(yīng)該是 modal.js 自己處理的。
但是我們寫了N年的前端卻一直這樣寫模塊,不是因?yàn)樗麑?duì),而是因?yàn)槲覀兞?xí)慣了這種錯(cuò)誤的方式?,F(xiàn)在用Vue我們可以完全封裝一個(gè)模塊的全部依賴,無(wú)論是模板、CSS還是JS,我們都不需要再去關(guān)心,只要引入這個(gè)模塊就可以使用,而模塊的依賴是它自己進(jìn)行處理的。
那么我們的依賴關(guān)系就變成了:
其中 modal.vue 包含了全部所需要的依賴,那么我們就不在需要自己去處理對(duì)應(yīng)的 CSS 甚至 模板了。這才是模塊化應(yīng)該達(dá)到的效果。
創(chuàng)建 Vue 項(xiàng)目
Vue 提供了一個(gè)工具 vue-cli 可以創(chuàng)建一個(gè)項(xiàng)目模板: https://github.com/vuejs/vue-cli
這里我先嘗試了一下另一個(gè)模板項(xiàng)目:https://github.com/vuejs-templates/webpack
然后我們就可以不用 純JS來(lái)寫模塊了,而是借助 webpack 來(lái)把一個(gè)模塊相關(guān)的所有內(nèi)容全部寫到一個(gè)文件中。以之前的 todo list 為例,其實(shí)上一章講的只是component的用法所以那樣寫了。我們改成一個(gè)更好的寫法如下:
List.vue:
<template> <ul> <li v-for='todo in list'> <label v-bind:class="{ done : todo.done }" > <input type="checkbox" v-model="todo.done"/> {{todo.title}} </label> </li> </ul> </template> <script> export default { props: { initList: { type: Array } }, data () { return { list: [] } }, events: { add (input) { if (!input) return false this.list.unshift({ title: input, done: false }) } } } </script> <style lang="less" scoped> ul { margin-left: 2rem; padding: 0; .done { text-decoration: line-through; } } </style>
Form.vue:
<template> <h1>{{username}}'s Todo List</h1> <form v-on:submit="add" v-on:submit.prevent> <input type="text" v-model="input"/> <input type="submit" value='add' /> </form> </template> <script> export default { props: { username: { type: String, default: 'Unnamed' } }, data () { return { input: '' } }, methods: { add () { this.$dispatch('add', this.input) this.input = '' } } } </script>
Todo.vue:
<template> <div id="todo"> <todo-form username='Lily'></todo-form> <todo-list></todo-list> </div> </template> <script> import Form from './Form.vue' import List from './List.vue' export default { components: { 'todo-form': Form, 'todo-list': List }, events: { add (input) { this.$broadcast('add', input) } } } </script> <style> </style>
App.vue:
<template> <todo></todo> </template> <script> import Todo from './components/Todo.vue' export default { components: { 'todo': Todo } } </script> <style> </style>
這樣我們就把之前的 Todo List 按照 模塊化 重寫了一遍。模塊化是構(gòu)建大型應(yīng)用的基礎(chǔ)之一,但是這一點(diǎn)還不夠,我們還需要做到:
•更好的狀態(tài)管理,把不同組件共享的 State 獨(dú)立出來(lái)管理
•自動(dòng)化測(cè)試
•路由等
這里我們只做其中一個(gè),就是把 State 獨(dú)立成一個(gè)單獨(dú)模塊。很顯然,對(duì)一個(gè) Todo List 應(yīng)用來(lái)說(shuō),保存 todo list 的數(shù)據(jù)結(jié)構(gòu)就是不同組件共享的 State。
之前我們?yōu)槭裁葱枰M(jìn)行事件廣播,就是因?yàn)椴煌M件之間要操作的數(shù)據(jù)就保存在 List.vue 中,所以在 Form.vue 中想增加一條數(shù)據(jù)的時(shí)候需要通過(guò)事件的方式去通知 List.vue 來(lái)添加。
也就是其實(shí)這個(gè)數(shù)據(jù)不是 List.vue 私有的,應(yīng)該至少是這兩個(gè)組件公有的,現(xiàn)在被 List.vue 據(jù)為己有之后,F(xiàn)orm.vue 沒法修改它只好通過(guò)事件進(jìn)行通知。
雖然事件的方式很優(yōu)雅,但其實(shí)我們可以做的更好,就是把數(shù)據(jù)獨(dú)立出來(lái),這樣 Form.vue 和 List.vue 都可以直接修改數(shù)據(jù),而不用那么麻煩發(fā)通知。
這里我們?cè)黾右粋€(gè) Store.js 文件:
export default { list: [ ], add (title) { if (!title) return this.list.unshift({ title: title, done: false }) } }
然后 我們可以把 List.vue 改成這樣,這里只貼出JS部分的代碼:
import Store from '../Store.js' export default { props: { initList: { type: Array } }, data () { return Store } }
Form.vue 也不需要廣播了,直接調(diào)用 Store.add 方法既可以添加:
import Store from '../Store.js' export default { props: { username: { type: String, default: 'Unnamed' } }, data () { return { input: '' } }, methods: { add () { Store.add(this.input) this.input = '' } } }
這樣一改之后,整個(gè)邏輯會(huì)清晰很多,并且應(yīng)用越是復(fù)雜,越是應(yīng)該抽出公有的 Store ,不然會(huì)出現(xiàn)廣播事件滿天飛的情況。
另外用這個(gè)項(xiàng)目模板之后,hot-reload 爽的不要不要的,刷新操作都省了。
上述的源碼在這里:https://github.com/lihongxun945/vue-webpack-todo-list
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 前端框架Vue.js中Directive知識(shí)詳解
- vue,angular,avalon這三種MVVM框架優(yōu)缺點(diǎn)
- Vue框架中正確引入JS庫(kù)的方法介紹
- vue.js中mint-ui框架的使用方法
- 使用vue框架 Ajax獲取數(shù)據(jù)列表并用BootStrap顯示出來(lái)
- Vue2.0 UI框架ElementUI使用方法詳解
- 前端框架學(xué)習(xí)總結(jié)之Angular、React與Vue的比較詳解
- 利用VUE框架,實(shí)現(xiàn)列表分頁(yè)功能示例代碼
- 基于Vuejs框架實(shí)現(xiàn)翻頁(yè)組件
- 小白教程|一小時(shí)上手最流行的前端框架vue(推薦)
相關(guān)文章
vue項(xiàng)目的創(chuàng)建的步驟(圖文教程)
本文主要介紹了vue項(xiàng)目的創(chuàng)建的步驟(圖文教程),文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03淺析webpack-bundle-analyzer在vue-cli3中的使用
這篇文章主要介紹了webpack-bundle-analyzer在vue-cli3中的使用,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-10-10Vue源碼學(xué)習(xí)之關(guān)于對(duì)Array的數(shù)據(jù)偵聽實(shí)現(xiàn)
這篇文章主要介紹了Vue源碼學(xué)習(xí)之關(guān)于對(duì)Array的數(shù)據(jù)偵聽實(shí)現(xiàn),Vue使用了一個(gè)方式來(lái)實(shí)現(xiàn)Array類型的監(jiān)測(cè)就是攔截器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-04-04vue-router實(shí)現(xiàn)組件間的跳轉(zhuǎn)(參數(shù)傳遞)
這篇文章主要為大家詳細(xì)介紹了vue-router實(shí)現(xiàn)組件間的跳轉(zhuǎn),參數(shù)傳遞方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11VUE Error: getaddrinfo ENOTFOUND localhost
這篇文章主要介紹了VUE Error: getaddrinfo ENOTFOUND localhost,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05VUE搭建分布式醫(yī)療掛號(hào)系統(tǒng)的前臺(tái)預(yù)約掛號(hào)步驟詳情
這篇文章主要介紹了VUE搭建分布式醫(yī)療掛號(hào)系統(tǒng)的前臺(tái)預(yù)約掛號(hào)步驟詳情,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04Vite結(jié)合whistle實(shí)現(xiàn)一勞永逸開發(fā)環(huán)境代理方案
這篇文章主要為大家介紹了Vite結(jié)合whistle實(shí)現(xiàn)一勞永逸開發(fā)環(huán)境代理方案,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07vue.js路由mode配置之去掉url上默認(rèn)的#方法
今天小編就為大家分享一篇vue.js路由mode配置之去掉url上默認(rèn)的#方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11解決vue3報(bào)錯(cuò):Unexpected?mutation?of?“xxx“?prop.(eslintvue/no
這篇文章主要給大家介紹了關(guān)于如何解決vue3報(bào)錯(cuò):Unexpected?mutation?of?“xxx“?prop.(eslintvue/no-mutating-props)的相關(guān)資料,文中通過(guò)代碼將解決辦法介紹的非常詳細(xì),需要的朋友可以參考下2023-12-12