摘要:社區(qū)的認(rèn)可目前已經(jīng)是相關(guān)最多的開源項(xiàng)目了,體現(xiàn)出了社區(qū)對(duì)其的認(rèn)可。監(jiān)聽事件手動(dòng)維護(hù)列表這樣我們就簡單的完成了拖拽排序。
完整項(xiàng)目地址:vue-element-admin
系類文章一:手摸手,帶你用vue擼后臺(tái) 系列一(基礎(chǔ)篇)
系類文章二:手摸手,帶你用vue擼后臺(tái) 系列二(登錄權(quán)限篇)
系類文章三:手摸手,帶你用vue擼后臺(tái) 系列三(實(shí)戰(zhàn)篇)
系類文章四:手摸手,帶你用vue擼后臺(tái) 系列四(vueAdmin 一個(gè)極簡的后臺(tái)基礎(chǔ)模板)
系類文章:手摸手,帶你優(yōu)雅的使用 icon
系類文章:手摸手,帶你封裝一個(gè)vue component
在前面兩篇文章中已經(jīng)把基礎(chǔ)工作環(huán)境構(gòu)建完成,也已經(jīng)把后臺(tái)核心的登錄和權(quán)限問題完成了,現(xiàn)在手摸手,一起進(jìn)入實(shí)操。
Element去年十月份開始用 vue 做管理后臺(tái)的時(shí)候毫不猶豫的就選擇了 element-ui,那時(shí)候 vue2.0 剛發(fā)布也沒多久,市面上也沒有很多其它的 vue2.0 的 ui 框架可供選擇。雖然 element-ui 也有很多的不足,前期的bug也不少,但我還是選擇了它,簡單說一下我選擇element-ui的原因吧:
有大廠背書 : 雖然核心開發(fā)只有兩三個(gè)人,但至少不用擔(dān)心哪天就不維護(hù),帶著小姨子跑路了
持續(xù)迭代 : element-ui發(fā)版至今release了四十多個(gè)版本,之前平均都是一周一個(gè)小版本更新(是不是不小心暴露了它bug多的問題/(ㄒoㄒ)/~~)(ps: 至2017.12.4 已經(jīng)迭代了74個(gè)版本,還保持著較高更新頻率)。
生態(tài)圈優(yōu)異,社區(qū)活躍 :其 contributors已經(jīng)有250多人(前期我有饒有興致的貢獻(xiàn)過幾個(gè)pr,參與過七八十個(gè)issue),社區(qū)里也有很多基于element-ui 的拓展組件,也有很多相關(guān)的 qq 討論群或者 gitter。
社區(qū)的認(rèn)可:目前Element已經(jīng)是vue相關(guān)最多star的開源項(xiàng)目了,體現(xiàn)出了社區(qū)對(duì)其的認(rèn)可。
說了這么多優(yōu)點(diǎn),作為一個(gè)資深element-ui用戶還是有些要抱怨的~和react老大哥 Ant Design 相比還是有一定的差距的,不管是組件的豐富性,參數(shù)的可配性還是文檔的完整性,亦或是UI的交互和美觀度。不過 ant 也是經(jīng)過了近9k次commit的不斷打磨,才有了今天。我也相信 element-ui也會(huì)越來越好的。
這里還有一些其它的框架(只討論pc端的框架)大家可以自行選擇:
ivew 一國人個(gè)人寫的框架,美觀度和交互性都不錯(cuò),有種介于Element和Ant之間的感覺,之前和element團(tuán)隊(duì)小小的撕了一下,有興趣的自己去圍觀吧,框架還是很不做的,一個(gè)人能做出這樣,也是很不容易的。作者公開信件
vue-admin 也是一個(gè)不錯(cuò)的選擇,代碼寫的和不錯(cuò),官方也出了一個(gè)admin的架子,也很值得借鑒
vue-material 一個(gè)material design vue框架庫
vuetify 又是一個(gè)material design vue框架庫
Keen-UI 又又是一個(gè)material design vue框架庫
CoreUI-Free-Bootstrap-Admin-Template 和以前的Bootstrap一樣,搭好了一個(gè)完整的架子,大家可以進(jìn)行二次拓展,它有vue,react,angular多個(gè)版本
Framework7-Vue 個(gè)人感覺這是本人體驗(yàn)到現(xiàn)在移動(dòng)端體驗(yàn)最好的框架。不過Framework7-Vue感覺還不是很完善,還需要觀望一段時(shí)間。而且它有自己的路由規(guī)則,所以不能使用 vue-router,這點(diǎn)還是很不方便的。
簡單列舉了一些主流的框架,不得不感慨現(xiàn)在vue的生態(tài)圈真是太繁榮了,上述框架樓主并沒有深入使用過,不好發(fā)表太多建議,大家自行甄別適合自己業(yè)務(wù)的框架吧。
這里開始我們會(huì)開始介紹一些結(jié)合Element的開發(fā)經(jīng)驗(yàn)。
基于Element的動(dòng)態(tài)換膚有些產(chǎn)品就是這么殘忍,能完成需求就不錯(cuò)了,還要讓我們做動(dòng)態(tài)換膚。Element官網(wǎng)上也提供了自定義主題的方案
同時(shí)也提供了一個(gè)在線自定義主題的demo
是不是很酷,作者也說明了實(shí)現(xiàn)的方案 地址,大概思路:
先把默認(rèn)主題文件中涉及到顏色的 CSS 值替換成關(guān)鍵詞
根據(jù)用戶選擇的主題色生成一系列對(duì)應(yīng)的顏色值
把關(guān)鍵詞再換回剛剛生成的相應(yīng)的顏色值
直接在頁面上加 style 標(biāo)簽,把生成的樣式填進(jìn)去
我看完覺得真的還是有點(diǎn)復(fù)雜的。有沒有簡單的方案呢?
讓我們思考一下,讓我們自己寫動(dòng)態(tài)換膚該怎么寫呢?最常見的方法就是寫兩套主題,一套叫day theme ,一套叫night theme,night theme主題 都在一個(gè).night-theme的命名空間下,我們動(dòng)態(tài)的在body上add .night-theme , remove .night-theme。這就是最簡單的動(dòng)態(tài)換膚。所以我們也能不能順著這個(gè)思路,基于 element-ui 實(shí)現(xiàn)動(dòng)態(tài)換膚呢?
首先我們下載官方通過的 Theme generator ,一個(gè)專門用來生成Element主題的工具。按照文檔,我們生成了需要的主題。
之后就是我們要做的事情了,將這個(gè)主題的每個(gè)元素外面包裹一個(gè)class 來做命名空間。
我們這里用到了gulp-css-wrap這個(gè)神器,輕輕松松就完成了我們想要的結(jié)果
var path = require("path") var gulp = require("gulp") var cleanCSS = require("gulp-clean-css"); var cssWrap = require("gulp-css-wrap"); var customThemeName=".custom-theme" gulp.task("css-wrap", function() { return gulp.src( path.resolve("./theme/index.css")) .pipe(cssWrap({selector:customThemeName})) .pipe(cleanCSS()) .pipe(gulp.dest("dist")); }); gulp.task("move-font", function() { return gulp.src(["./theme/fonts/**"]).pipe(gulp.dest("dist/fonts")); }); gulp.task("default",["css-wrap","move-font"]);
這樣就得到了一個(gè)以.custom-theme為命名空間的自定義主題了,之后我們?cè)陧?xiàng)目中引入主題
//main.js import "assets/custom-theme/index.css"
我們?cè)趽Q膚的地方toggleClass(document.body, "custom-theme")一直toggle body 的 class就可以了。我們就簡單實(shí)現(xiàn)了動(dòng)態(tài)換膚效果。
不過這種模式實(shí)現(xiàn)換膚也是有一個(gè)弊端的,它等于把這兩個(gè)主題都打包在了項(xiàng)目里,如果你的項(xiàng)目主題需要七八種,這種模式就不適合了。我們就需要?jiǎng)討B(tài)的加載css,下面就是最簡單的動(dòng)態(tài)添加css的例子,當(dāng)然你可以封裝一下,增加成功或者失敗回調(diào),判斷是否加載過改資源等等就不展開了。
var head = document.getElementsByTagName("HEAD").item(0); var style = document.createElement("link"); style.href = "style.css"; style.rel = "stylesheet"; style.type = "text/css"; head.appendChild(style);
更新(2017.12)
element-ui 官方更新了2.0版本,同時(shí)也提供了一個(gè)新的換膚思路。
文檔
這里又有談一下導(dǎo)航欄的問題,本項(xiàng)目里的側(cè)邊欄是根據(jù) router.js 配置的路由并且根據(jù)權(quán)限動(dòng)態(tài)生成的,這樣就省去了寫一遍路由還要手動(dòng)再寫一次側(cè)邊欄這種麻煩事,但也遇到了一個(gè)問題,路由可能會(huì)有多層嵌套,很多人反饋?zhàn)约旱膫?cè)邊欄會(huì)有三級(jí),甚至還有五級(jí)的。所以重構(gòu)了一下側(cè)邊欄,使用了遞歸組件,這樣不管你多少級(jí),都能愉快的顯示了。代碼
側(cè)邊欄高亮問題: 很多人在群里問為什么自己的側(cè)邊欄不能跟著自己的路由高亮,其實(shí)很簡單,element-ui官方已經(jīng)給了default-active所以我們只要
:default-active="$route.path"
將default-active一直指向當(dāng)前路由就可以了,就是這么簡單。
點(diǎn)擊側(cè)邊欄 刷新當(dāng)前路由
在用 spa(單頁面開發(fā)) 這種開發(fā)模式之前,大部分都是多頁面后臺(tái),用戶每次點(diǎn)擊側(cè)邊欄都會(huì)重新請(qǐng)求這個(gè)頁面,用戶漸漸養(yǎng)成了點(diǎn)擊側(cè)邊欄當(dāng)前路由來刷新頁面的習(xí)慣。但現(xiàn)在 spa 就不一樣了,用戶點(diǎn)擊當(dāng)前高亮的路由并不會(huì)刷新view,因?yàn)?b>vue-router會(huì)攔截你的路由,它判斷你的url并沒有任何變化,所以它不會(huì)觸發(fā)任何鉤子或者是view的變化。issue地址,社區(qū)也對(duì)該問題展開了激烈討論。
尤大本來也說要增加一個(gè)方法來強(qiáng)刷view,但后來他又改變了心意/(ㄒoㄒ)/~~。但需要就擺在這里,我們?cè)撛趺崔k呢?他說了不改變current URL 就不會(huì)觸發(fā)任何東西,那我可不可以強(qiáng)行觸發(fā)東西你?上有政策, 下有對(duì)策我們變著花來hack。方法也很簡單,通過不斷改變url的query來觸發(fā)view的變化。我們監(jiān)聽側(cè)邊欄每個(gè)link 的 click事件,每次點(diǎn)擊都給router push 一個(gè)不一樣的query 來確保會(huì)重新刷新view。
clickLink(path) { this.$router.push({ path, query: { t: +new Date() //保證每次點(diǎn)擊路由的query項(xiàng)都是不一樣的,確保會(huì)重新刷新view } }) }
但這也有一個(gè)弊端就是 url 后面有一個(gè)很難看的 query 后綴如 xxx.com/article/list?t=1496832345025,但我司用戶們表示能接受。。。只能暫時(shí)這樣hack了,不知道大家有沒有更好的方法,學(xué)習(xí)學(xué)習(xí)。
Table經(jīng)過好幾個(gè)版本的迭代,element-ui 的table組件已經(jīng)能滿足大部分業(yè)務(wù)需求了。不過rowSpan colSpan表格行/列合并現(xiàn)在并不是支持(element-ui2.0版本之后開始支持)。官方對(duì)此功能的更新情況可以關(guān)注這個(gè)issue。
這里我著重講一下table表格幾個(gè)常用的業(yè)務(wù)形態(tài)。
Table 拖拽排序
這里主要是基于Sortable
import Sortable from "sortablejs" let el = document.querySelectorAll(".el-table__body-wrapper > table > tbody")[0] let sortable = Sortable.create(el)
在table mounted之后申明Sortable.create(el) table的每行tr就可以隨意拖拽了,麻煩的目前我們的排序都是基于dom的,我們的數(shù)據(jù)層list并沒有隨之改變。所以我們就要手動(dòng)的來管理我們的列表。
this.sortable = Sortable.create(el, { onEnd: evt => { //監(jiān)聽end事件 手動(dòng)維護(hù)列表 const tempIndex = this.newList.splice(evt.oldIndex, 1)[0]; this.newList.splice(evt.newIndex, 0, tempIndex); } });
這樣我們就簡單的完成了 table 拖拽排序。這里如果不是基于 dom 的排序推薦使用Vue.Draggable。完整代碼
Table 內(nèi)聯(lián)編輯table內(nèi)聯(lián)編輯也是一個(gè)常見的需求。
其實(shí)也很簡單,當(dāng)我們拿到 list 數(shù)據(jù)之后先洗一下數(shù)據(jù),每一條數(shù)據(jù)里面插入一個(gè)edit[ true or false ]判斷符,來表示當(dāng)前行是否處于編輯狀態(tài)。之后就是通過v-show動(dòng)態(tài)切換不同的相應(yīng)view就可以了。完整代碼
Table 常見坑{{ scope.row.title }} 編輯 完成
通過dialog來編輯,新建,刪除table的元素這種業(yè)務(wù)場景相對(duì)于前面說的兩種更加的常見。而且也有不少的小坑。
首先我們要明確一個(gè)點(diǎn) vue 是一個(gè)MVVM框架,我們傳統(tǒng)寫代碼是命令式編程,拿到table這個(gè)dom之后就是命令式對(duì)dom增刪改。而我們現(xiàn)在用聲明式編程,只用關(guān)注data的變化就好了,所以我們這里的增刪改都是基于list這個(gè)數(shù)組來的。這里我們還要明確一點(diǎn)vue 列表渲染注意事項(xiàng)
由于 JavaScript 的限制, Vue 不能檢測以下變動(dòng)的數(shù)組:
* 當(dāng)你利用索引直接設(shè)置一個(gè)項(xiàng)時(shí),例如: vm.items[indexOfItem] = newValue
所以我們想改變table中第一條數(shù)據(jù)的值,通過this.list[0]=newValue這樣是不會(huì)生效的。
解決方案: // Array.prototype.splice` example1.items.splice(indexOfItem, 1, newValue)
所以我們可以通過
//添加數(shù)據(jù) this.list.unshift(this.temp); //刪除數(shù)據(jù) const index = this.list.indexOf(row); //找到要?jiǎng)h除數(shù)據(jù)在list中的位置 this.list.splice(index, 1); //通過splice 刪除數(shù)據(jù) //修改數(shù)據(jù) const index = this.list.indexOf(row); //找到修改的數(shù)據(jù)在list中的位置 this.list.splice(index, 1,this.updatedData); //通過splice 替換數(shù)據(jù) 觸發(fā)視圖更新
這樣我們就完成了對(duì)table的增刪改操作,列表view也自動(dòng)響應(yīng)發(fā)生了變化。這里在修改數(shù)據(jù)的時(shí)候還有一個(gè)小坑需要主要。
當(dāng)我們拿到需要修改行的數(shù)據(jù)時(shí)候不能直接將它直接賦值給dialog,不然會(huì)發(fā)生下面的問題。
如上圖所示,我們?cè)赿ialog里面改變狀態(tài)的時(shí)候,遮罩下面的table里面該行的狀態(tài)也在那里跟著一只變化著。原因想必大家都猜到了。賦值的數(shù)據(jù)是一個(gè)objec引用類型共享一個(gè)內(nèi)存區(qū)域的。所以我們就不能直接連等復(fù)制,需要重新指向一個(gè)新的引用,方案如下:
//賦值對(duì)象是一個(gè)obj this.objData=Object.assign({}, row) //這樣就不會(huì)共用同一個(gè)對(duì)象 //數(shù)組我們也有一個(gè)巧妙的防范 newArray = oldArray.slice(); //slice會(huì)clone返回一個(gè)新數(shù)組Tabs
tab在后臺(tái)項(xiàng)目中也比較常用的。假設(shè)我們有四個(gè)tab選項(xiàng),每個(gè)tab都會(huì)向后端請(qǐng)求數(shù)據(jù),但我們希望一開始只會(huì)請(qǐng)求當(dāng)前的tab數(shù)據(jù),而且tab來回切換的時(shí)候不會(huì)重復(fù)請(qǐng)求,只會(huì)實(shí)例化一次。首先我們想到的就是用v-if 這樣的確能做到一開始不會(huì)掛載后面的tab,但有一個(gè)問題,每次點(diǎn)擊這個(gè)tab組件都會(huì)重新掛載一次,這是我們不想看到的,這時(shí)候我們就可以用到
keep-alive 包裹動(dòng)態(tài)組件時(shí),會(huì)緩存不活動(dòng)的組件實(shí)例,而不是銷毀它們。 它是一個(gè)抽象組件:它自身不會(huì)渲染一個(gè) DOM 元素,也不會(huì)出現(xiàn)在父組件鏈中。
所以我們就可以這樣寫tabs了
Select 選擇器
Select 選擇器直接使用沒有什么太多問題,但很多時(shí)候我們需要通過Select來回顯一些數(shù)據(jù),當(dāng)我們
這里推薦一下vue-multiselect 它能完美的解決前面Element select的問題。目前也是vue component 中比較好用的一個(gè),ui也非常的好看,建議大家可以嘗試性用一下,真的非常的不錯(cuò)。
Upload本身沒什么好說的,文檔寫的蠻清楚了。這里主要說一下怎么將Upload組件和七牛直傳結(jié)合在一起。
這里我們選擇api直傳的方式,就是我們首先要通過后端(go,node,php都可以)文檔生成七牛上傳必要的token(上傳憑證)和key(資源的最終名稱)。
所以現(xiàn)在只要想辦法講token和key塞進(jìn)post請(qǐng)求里面就可以了,好在官方也提供了這個(gè)方法。
。但怎么才能先異步的拿到token再將它塞入請(qǐng)求里呢?
這時(shí)候我們又發(fā)現(xiàn)了before-upload 這個(gè)鉤子還支持promise簡直合我們的心意。
但我們寫著寫著怎樣才能動(dòng)態(tài)的改變之前的dataObj呢?通過看源碼發(fā)現(xiàn)我們可以_self._data這樣子拿到我們想要的數(shù)據(jù)。線上代碼
jsx 將文件拖到此處,或點(diǎn)擊上傳
在使用Element的時(shí)候,官方提供了很多可以自己寫render function的地方,但由于Element內(nèi)部都是用jsx 寫render function的,所以demo也都是jsx,但很多人自己項(xiàng)目中其實(shí)是沒有安裝的,導(dǎo)致報(bào)錯(cuò)。但說真的用createElement裸寫render 函數(shù)還是有些蛋疼。我們要用jsx,首先要安裝 babel-plugin-transform-vue-jsx 安裝方法如下:
npm install babel-plugin-syntax-jsx babel-plugin-transform-vue-jsx babel-helper-vue-jsx-merge-props babel-preset-es2015 --save-dev
.babelrc:文件
{ "presets": ["es2015"], "plugins": ["transform-vue-jsx"] }
這樣我們就可以愉快的使用 jsx 寫render function了。
element 常見問題click事件不觸發(fā)問題:一直有人在群里問
官方說明了所有的原生事件必須添加 .native 修飾符。
修改element樣式問題: 用ui組件總免不了需要對(duì)它做一些個(gè)性化定制的需求,所以我們就要覆蓋element的一些樣式。
首先我們要了解一下vue scoped是什么,很多人非常喜歡用scoped,媽媽再也不用擔(dān)心樣式?jīng)_突問題了,其實(shí)scoped也沒有很神秘的,它就是基于PostCss的,加了一個(gè)作用局的概念。
//編譯前 .example { color: red; } //編譯后 .example[_v-f3f3eg9] { color: red; }
它和我們傳統(tǒng)的命名空間的方法避免css沖突沒有什么本質(zhì)性的區(qū)別。
現(xiàn)在我們來說說怎么覆蓋element-ui樣式。由于element-ui的樣式我們是在全局引入的,所以你想在某個(gè)view里面覆蓋它的樣式就不能加scoped,但你又想只覆蓋這個(gè)頁面的element樣式,你就可在它的父級(jí)加一個(gè)class,以用命名空間來解決問題。
.aritle-page{ //你的命名空間 .el-tag { //element-ui 元素 margin-right: 0px; } }
建議向樓主一樣專門建一個(gè)scss文件里專門自定義element-ui的各種樣式。線上代碼
其它關(guān)于element相關(guān)的東西真的沒有什么好說的了,人家文檔和源碼就放在那里,有問題就去看文檔,再去issue里找找,再去看看源碼,大部分問題都能解決了。給一個(gè)訣竅其實(shí)大部分詭異的問題都可以通過加一個(gè)key或者
Vue.nextTick來解決。。
管理后臺(tái)富文本也是一個(gè)非常重要的功能,樓主在這里也踩了不少的坑。樓主在項(xiàng)目里最終選擇了 tinymce
這里在簡述一下推薦使用tinymce的原因:tinymce 是一家老牌做富文本的公司(這里也推薦 ckeditor,也是一家一直做富文本的公司,新版本很不錯(cuò)),它的產(chǎn)品經(jīng)受了市場的認(rèn)可,不管是文檔還是配置的自由度都很好。在使用富文本的時(shí)候有一點(diǎn)也很關(guān)鍵就是復(fù)制格式化,之前在用一款韓國人做的富文本summernote被它的格式化坑的死去活來,但 tinymce 的去格式化相當(dāng)?shù)暮茫€有一個(gè)增值項(xiàng)目就是powerpaste,那是無比的強(qiáng)大,支持從word里面復(fù)制各種東西,都不會(huì)有問題。富文本還有一點(diǎn)也很關(guān)鍵,就是拓展性。樓主用tinymce寫了好幾個(gè)插件,學(xué)習(xí)成本和容易度都不錯(cuò),很方便拓展。最后一點(diǎn)就是文檔很完善,基本你想得到的配置項(xiàng),它都有。tinymce也支持按需加載,你可以通過它官方的build頁定制自己需要的plugins。
我再來分析一下市面上其它的一些富文本:
summernote 先來說一個(gè)我絕對(duì)不推薦的富文本。這是一個(gè)韓國人開源的富文本(當(dāng)然不推薦的理由不是因?yàn)檫@個(gè)),它對(duì)很多富文本業(yè)界公認(rèn)的默認(rèn)行為理解是反起到而行的,而且只為用了一個(gè)dialog的功能,引入了boostrap,一堆人抗議就是不改。格式化也是差勁。。反正不要用!不要用!不要用!
ckeditor ckeditor也是一家老牌做富文本的公司,樓主舊版后臺(tái)用的就是這個(gè),今年也出了5.0版本,ui也變美觀了不少,相當(dāng)?shù)牟诲e(cuò),而且它號(hào)稱是插件最豐富的富文本了。推薦大家也可以試用一下。
quill 也是一個(gè)非常火的富文本,長相很不錯(cuò)。基于它寫插件也很簡單,api設(shè)計(jì)也很簡單。樓主不選擇它的原因是它對(duì)圖片的各種操作不友善,而且很難改。如果對(duì)圖片沒什么操作的用戶,推薦使用。
medium-editor 大名鼎鼎的medium的富文本(非官方出品),但完成度還是不很不錯(cuò),拓展性也不錯(cuò)。不過我覺得大部分用戶還是會(huì)不習(xí)慣medium這種寫作方式的。
Squire 一個(gè)比較輕量的富文本,壓縮完才11.5kb,相對(duì)于其它的富文本來說是非常的小了,推薦功能不復(fù)雜的建議使用。
wangEditor 一個(gè)國人寫的富文本,用過感覺還是不錯(cuò)的。不過畢竟是個(gè)人的,不像專門公司做富文本的,配置型和豐富性不足。前端幾大禁忌就有富文本 為什么都說富文本編輯器是天坑?,不過個(gè)人能做成這樣子很不容易了。
百度UEditor 沒有深入使用過,只在一個(gè)angular1X的項(xiàng)目簡單用過,不過說著的ui真的不好看,不符合當(dāng)今審美了,官方也已經(jīng)很久沒跟新過了。
樓主列舉了很多富文本但并沒有列舉任何 vue 相關(guān)的富文本,主要是因?yàn)楦晃谋菊娴谋认胂笾袕?fù)雜,在前面的文章里也說過了,其實(shí)用 vue 封裝組件很方便的,沒必要去用人家封裝的東西什么vue-quill vue-editor這種都只是簡單包了一層,沒什么難度的。還不如自己來封裝,靈活性可控性更強(qiáng)一點(diǎn)。還有一點(diǎn)基于 vue 真沒什么好的富文本,不像 react 有 facebook 出的 draft-js,ory 出的 editor,這種大廠出的產(chǎn)品。
當(dāng)然你也可以選擇一些付費(fèi)的富文本編輯器,作者自己公司里面有一個(gè)項(xiàng)目就使用了 froala-editor 這款編輯器。不管是美觀和易用性都是不錯(cuò)的,公司買的是專業(yè)版,一年也就 $349 ,價(jià)格也是很合理的,但其實(shí)省去的程序員開發(fā)陳本可能遠(yuǎn)不止這個(gè)價(jià)錢。
Tinymce這里來簡單講一下在自己項(xiàng)目中使用 Tinymce 的方法。
由于目前使用 npm 安裝 Tinymce 方法比較負(fù)責(zé)復(fù)雜而且還有一些問題(日后可能會(huì)采用該模式)。
目前采用全局引用的方式。代碼地址:static/tinymce static目錄下的文件不會(huì)被打包, 在 index.html 中引入。
使用
由于富文本不適合雙向數(shù)據(jù)流,所以只會(huì) watch 傳入富文本的內(nèi)容一次變化,只會(huì)就不會(huì)再監(jiān)聽了,如果之后還有改變富文本內(nèi)容的需求。
可以通過 this.refs.xxx.setContent() 來設(shè)置
源碼也很簡單,有任何別的需求都可以在 @/components/Tinymce/index.vue 中自行修改。
Markdownmarkdown 我們這里選用了 simplemde-markdown-editor ,簡單的用vue封裝了一下地址,如果需求方能接受 markdown 就一定要用 markdown,坑真心會(huì)比富文本少很多。這里我們用markdown做了編輯器,還需要一個(gè)能解析的的東西。可以你傳給后端讓后端幫你轉(zhuǎn)化,也可以前端自己來,這里推薦一個(gè)轉(zhuǎn)化庫showdown。使用方法:
import("showdown").then(showdown => { //用了 Dynamic import const converter = new showdown.Converter();//初始化 this.html = converter.makeHtml(this.content)//轉(zhuǎn)化 })
用法也很簡單兩行代碼就完成了markdown to html,當(dāng)然它還有很多個(gè)性畫的配置,大家有需求自行研究吧。
導(dǎo)出excel這里先明確一點(diǎn),如果你的業(yè)務(wù)需求對(duì)導(dǎo)出文件的格式?jīng)]有什么要求,不建議導(dǎo)出成xlsx格式的,直接導(dǎo)出成csv的就好了,真的會(huì)簡單很多。創(chuàng)建一個(gè)a標(biāo)簽,寫上data:text/csv;charset=utf-8頭,再把數(shù)據(jù)塞進(jìn)去,encodeURI(csvContent)一下就好了,詳情就不展開了,大家可以借鑒這個(gè)stackoverflow回答。
我們重點(diǎn)說一下轉(zhuǎn)xlsx,我們這里用到了js-xlsx,一個(gè)功能很強(qiáng)大excel處理庫,只是下載各種格式excel,還支持讀取excel,但上手難度也非常大,相當(dāng)?shù)膹?fù)雜,其中涉及不少二進(jìn)制相關(guān)的東西。不過好在官方給了我們一個(gè)demo例子,我們寫不來還抄不來么,于是我們就借鑒官方的例子來改造了一下,具體原理就不詳細(xì)說了,真的很復(fù)雜。。。
重點(diǎn)是我們?cè)趺词褂茫∈紫任覀兎庋b一個(gè)Export2Excel.js,
它又依賴三個(gè)庫
require("script-loader!file-saver"); //保存文件用 require("script-loader!vendor/Blob"); //轉(zhuǎn)二進(jìn)制用 require("script-loader!xlsx/dist/xlsx.core.min"); //xlsx核心 由于這幾個(gè)文件不支持import引入,所以我們需要`script-loader`來將他們掛載到全局環(huán)境下。
它暴露了兩個(gè)接口export_table_to_excel和export_json_to_excel,我們常用export_json_to_excel因?yàn)楦拥目煽匾稽c(diǎn),我們可以自由的洗數(shù)據(jù)。
handleDownload() { require.ensure([], () => { // 用 webpack Code Splitting xlsl還是很大的 const { export_json_to_excel } = require("vendor/Export2Excel"); const tHeader = ["序號(hào)", "文章標(biāo)題", "作者", "閱讀數(shù)", "發(fā)布時(shí)間"]; // excel 表格頭 const filterVal = ["id", "title", "author", "pageviews", "display_time"]; const list = this.list; const data = this.formatJson(filterVal, list); // 自行洗數(shù)據(jù) 按序排序的一個(gè)array數(shù)組 export_json_to_excel(tHeader, data, "列表excel"); }) }, formatJson(filterVal, jsonData) { return jsonData.map(v => filterVal.map(j => v[j])) }
完整顯示線上代碼
ECharts管理后臺(tái)圖表也是常見得需求。這里圖表就只推薦ECharts,功能齊全,社區(qū)demo也豐富gallery。我還是那個(gè)觀點(diǎn),大部分插件建議大家還是自己用vue來包裝就好了,真的很簡單。ECharts支持webpack引入,圖省事可以將ECharts整個(gè)引入var echarts = require("echarts");不過ECharts還是不小的,我們大部分情況只是用到很少一部分功能,我平時(shí)習(xí)慣于按需引入的。
// 引入 ECharts 主模塊 var echarts = require("echarts/lib/echarts"); // 引入柱狀圖 require("echarts/lib/chart/bar"); // 引入提示框和標(biāo)題組件 require("echarts/lib/component/tooltip"); require("echarts/lib/component/title");
webpack中使用ECharts文檔
ECharts按需引入模塊文檔
接下來我們就要在vue中聲明初始化ECharts了。因?yàn)镋Charts初始化必須綁定dom,所以我們只能在vue的mounted生命周期里初始化。
mounted() { this.initCharts(); }, methods: { this.initCharts() { this.chart = echarts.init(this.$el); this.setOptions(); }, setOptions() { this.chart.setOption({ title: { text: "ECharts 入門示例" }, tooltip: {}, xAxis: { data: ["襯衫", "羊毛衫", "雪紡衫", "褲子", "高跟鞋", "襪子"] }, yAxis: {}, series: [{ name: "銷量", type: "bar", data: [5, 20, 36, 10, 10, 20] }] }) } }
就這樣簡單,ECharts就配置完成了,這時(shí)候你想說我的data是遠(yuǎn)程獲取的,或者說我動(dòng)態(tài)改變ECharts的配置該怎么辦呢?我們可以通過watch來觸發(fā)setOptions方法
//第一種 watch options變化 利用vue的深度 watcher,options一有變化就重新setOption watch: { options: { handler(options) { this.chart.setOption(this.options) }, deep: true }, } //第二種 只watch 數(shù)據(jù)的變化 只有數(shù)據(jù)變化時(shí)觸發(fā)ECharts watch: { seriesData(val) { this.setOptions({series:val}) } }
其實(shí)都差不多,還是要結(jié)合自己業(yè)務(wù)來封裝。后面就和平時(shí)使用ECharts沒有什么區(qū)別了。題外話ECharts的可配置項(xiàng)真心多,大家使用的時(shí)候可能要花一點(diǎn)時(shí)間了解它的api的。知乎有個(gè)問題:百度還有什么比較良心的產(chǎn)品?答案:ECharts,可見ECharts的強(qiáng)大與好用。
相同component 不同參數(shù)創(chuàng)建與編輯
其實(shí)后臺(tái)創(chuàng)建與編輯功能是最常見的了,它區(qū)別去前臺(tái)項(xiàng)目多了改的需求,但大部分創(chuàng)建頁面與編輯頁面字段和ui幾乎是一樣的,所以我們準(zhǔn)備公用一個(gè)component來對(duì)應(yīng)不同的頁面。有兩種常見的方法,來區(qū)別創(chuàng)建與編輯。
通過路由path的方式
這種方式最簡單暴力,我自己的項(xiàng)目中使用這種方式,通過約定路徑中出現(xiàn)"edit"就判斷為編輯模式。比較省力和方便,不過這是要在大家寫路徑的時(shí)候都按照規(guī)范來寫的前提下。
通過meta來區(qū)分
比較推薦這種方式來區(qū)分。
computed: { isEdit() { return this.$route.meta.isEdit // 根據(jù)meta判斷 // return this.$route.path.indexOf("edit") !== -1 // 根據(jù)路由判斷 } }, created() { if (this.isEdit) { this.fetchData(); } },
就這樣簡單的實(shí)現(xiàn)了多路由復(fù)用了一個(gè)component,其實(shí)不只是創(chuàng)建和編輯可以這樣用,如兩個(gè)列表的一模一樣,只是一個(gè)是內(nèi)部文章另一個(gè)是調(diào)取外部文章都能復(fù)用組件,通過meta的方式來判斷調(diào)取不同的接口。
占坑常規(guī)占坑,這里是手摸手,帶你用vue擼后臺(tái)系列。
完整項(xiàng)目地址:vue-element-admin
系類文章一:手摸手,帶你用vue擼后臺(tái) 系列一(基礎(chǔ)篇)
系類文章二:手摸手,帶你用vue擼后臺(tái) 系列二(登錄權(quán)限篇)
系類文章三:手摸手,帶你用vue擼后臺(tái) 系列三(實(shí)戰(zhàn)篇)
系類文章四:手摸手,帶你用vue擼后臺(tái) 系列四(vueAdmin 一個(gè)極簡的后臺(tái)基礎(chǔ)模板)
系類文章:手摸手,帶你優(yōu)雅的使用 icon
系類文章:手摸手,帶你封裝一個(gè)vue component
樓主個(gè)人免費(fèi)圈子
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/83437.html
摘要:靈活性和針對(duì)性。所以我覺得大部分組件還是自己封裝來的更為方便和靈活一些。動(dòng)手開干接下來我們一起手摸手教改造包裝一個(gè)插件,只要幾分鐘就可以封裝一個(gè)專屬于你的。 項(xiàng)目地址:vue-countTo配套完整后臺(tái)demo地址:vue-element-admin系類文章一:手摸手,帶你用vue擼后臺(tái) 系列一(基礎(chǔ)篇)系類文章二:手摸手,帶你用vue擼后臺(tái) 系列二(登錄權(quán)限篇)系類文章三:手摸手,帶...
摘要:詳細(xì)具體的使用可以見文章手摸手,帶你優(yōu)雅的使用。為了加速線上鏡像構(gòu)建的速度,我們利用源進(jìn)行加速并且將一些常見的依賴打入了基礎(chǔ)鏡像,避免每次都需要重新下載。 完整項(xiàng)目地址:vue-element-admin系類文章二:手摸手,帶你用vue擼后臺(tái) 系列二(登錄權(quán)限篇)系類文章三:手摸手,帶你用vue擼后臺(tái) 系列三(實(shí)戰(zhàn)篇)系類文章四:手摸手,帶你用vue擼后臺(tái) 系列四(vueAdmin 一...
摘要:我們將登錄按鈕上綁上事件,點(diǎn)擊登錄之后向服務(wù)端提交賬號(hào)和密碼進(jìn)行驗(yàn)證。所以前端和后端權(quán)限的劃分是不太一致。側(cè)邊欄最后一個(gè)涉及到權(quán)限的地方就是側(cè)邊欄,不過在前 完整項(xiàng)目地址:vue-element-admin 系列文章: 手摸手,帶你用vue擼后臺(tái) 系列一(基礎(chǔ)篇) 手摸手,帶你用vue擼后臺(tái) 系列二(登錄權(quán)限篇) 手摸手,帶你用vue擼后臺(tái) 系列三 (實(shí)戰(zhàn)篇) 手摸手,帶你用vu...
摘要:社區(qū)的認(rèn)可目前已經(jīng)是相關(guān)最多的開源項(xiàng)目了,體現(xiàn)出了社區(qū)對(duì)其的認(rèn)可。監(jiān)聽事件手動(dòng)維護(hù)列表這樣我們就簡單的完成了拖拽排序。 完整項(xiàng)目地址:vue-element-admin 系類文章一:手摸手,帶你用vue擼后臺(tái) 系列一(基礎(chǔ)篇)系類文章二:手摸手,帶你用vue擼后臺(tái) 系列二(登錄權(quán)限篇)系類文章三:手摸手,帶你用vue擼后臺(tái) 系列三(實(shí)戰(zhàn)篇)系類文章四:手摸手,帶你用vue擼后臺(tái) 系列...
摘要:目前的技術(shù)棧主要的采用由于是個(gè)人項(xiàng)目,所以數(shù)據(jù)請(qǐng)求都是用了代替。后續(xù)會(huì)出一系列的教程配套文章,如如何從零構(gòu)建后臺(tái)項(xiàng)目框架,如何做完整的用戶系統(tǒng)如權(quán)限驗(yàn)證,二次登錄等,如何二次開發(fā)組件如富文本,如何整合七牛等等文章,各種后臺(tái)開發(fā)經(jīng)驗(yàn)等等。 完整項(xiàng)目地址:vue-element-admin系類文章一:手摸手,帶你用vue擼后臺(tái) 系列一(基礎(chǔ)篇)系類文章二:手摸手,帶你用vue擼后臺(tái) 系列二...
閱讀 2202·2021-10-18 13:28
閱讀 2511·2021-10-11 10:59
閱讀 2340·2019-08-29 15:06
閱讀 1131·2019-08-26 13:54
閱讀 807·2019-08-26 13:52
閱讀 3148·2019-08-26 12:02
閱讀 2998·2019-08-26 11:44
閱讀 2511·2019-08-26 10:56