完整項目地址:vue-element-admin
系類文章一:手摸手窍奋,帶你用vue擼后臺 系列一(基礎(chǔ)篇)
系類文章二:手摸手茅坛,帶你用vue擼后臺 系列二(登錄權(quán)限篇)
前言
在前面兩篇文章中已經(jīng)把基礎(chǔ)工作環(huán)境構(gòu)建完成险耀,也已經(jīng)把后臺核心的登錄和權(quán)限完成了弄喘,現(xiàn)在手摸手,一起進入實操甩牺。
Element
去年十月份開始用vue做管理后臺的時候毫不猶豫的就選擇了Elemen蘑志,那時候vue2 剛發(fā)沒多久,市面上也沒有很多其它的vue2的ui框架。雖然Element也有很多的不足急但,前期的bug也不少澎媒,但我還是選擇了它,說一下我選擇Element的原因吧:
- 有大廠背書 : 雖然核心開發(fā)只有三個人波桩,但至少不用擔(dān)心哪天就不維護戒努,帶著小姨子跑路了。
- 持續(xù)迭代 : Element發(fā)版至今release了四十多個版本镐躲,之前平均都是一周一個小版本更新(是不是不小心暴露了它bug多的問題/(ㄒoㄒ)/~~)
- 生態(tài)圈優(yōu)異储玫,社區(qū)活躍 :其 contributors已經(jīng)有160多人(前期我有饒有興致的貢獻過幾個pr,參與過七八十個issue)萤皂,社區(qū)里也有很多基于Element 的拓展組件撒穷,也有很多相關(guān)的qq討論群或者 gitter。
- 社區(qū)的認(rèn)可:目前Element已經(jīng)是vue相關(guān)最多star的開源項目了裆熙,體現(xiàn)出了社區(qū)對其的認(rèn)可端礼。
說了這么多優(yōu)點,作為一個資深Element用戶還是有些要抱怨的~和react老大哥 Ant Design 相比還是有一定的差距的入录,不管是組件的豐富性蛤奥,參數(shù)的可配性還是文檔的完整性,亦或是UI的交互和美觀度僚稿。不過 ant 也是經(jīng)過了近9k次commit的不斷打磨喻括,才有了今天。我也相信 Element也會越來越好的贫奠。
這里還有一些其它的框架(只討論pc端的框架)大家可以自行選擇:
- ivew 一國人個人寫的框架唬血,美觀度和交互性都不錯,有種介于Element和Ant之間的感覺唤崭,之前和element團隊小小的撕了一下拷恨,有興趣的自己去圍觀吧,框架還是很不做的谢肾,一個人能做出這樣腕侄,也是很不容易的。作者公開信件
- vue-admin 也是一個不錯的選擇芦疏,代碼寫的和不錯冕杠,官方也出了一個admin的架子,也很值得借鑒
- vue-material 一個material design vue框架庫
- vuetify 又是一個material design vue框架庫
- Keen-UI 又又是一個material design vue框架庫
- CoreUI-Free-Bootstrap-Admin-Template 和以前的Bootstrap一樣酸茴,搭好了一個完整的架子分预,大家可以進行二次拓展,它有vue,react,angular多個版本
簡單列舉了一些主流的框架薪捍,不得不感慨現(xiàn)在vue的生態(tài)圈真是太繁榮了笼痹,上述框架樓主并沒有深入使用過配喳,不好發(fā)表太多建議,大家自行甄別適合自己業(yè)務(wù)的框架吧凳干。
這里開始我們會開始介紹一些結(jié)合Element的開發(fā)經(jīng)驗晴裹。
基于Element的動態(tài)換膚
有些產(chǎn)品就是這么殘忍,能完成需求就不錯了救赐,還要讓我們做動態(tài)換膚涧团。Element官網(wǎng)上也提供了自定義主題的方案
同時也提供了一個在線自定義主題的demo
是不是很酷,作者也說明了實現(xiàn)的方案 地址,大概思路:
- 先把默認(rèn)主題文件中涉及到顏色的 CSS 值替換成關(guān)鍵詞
- 根據(jù)用戶選擇的主題色生成一系列對應(yīng)的顏色值
- 把關(guān)鍵詞再換回剛剛生成的相應(yīng)的顏色值
- 直接在頁面上加 style 標(biāo)簽经磅,把生成的樣式填進去
我看完覺得真的還是有點復(fù)雜的少欺。有沒有簡單的方案呢?
讓我們思考一下馋贤,讓我們自己寫動態(tài)換膚該怎么寫呢赞别?最常見的方法就是寫兩套主題,一套叫day theme 配乓,一套叫night theme仿滔,night theme主題 都在一個.night-theme的命名空間下,我們動態(tài)的在body上add .night-theme ; remove .night-theme犹芹。這就是最簡單的動態(tài)換膚崎页。所以我們也能不能順著這個思路,基于Element實現(xiàn)動態(tài)換膚呢腰埂?
首先我們下載官方通過的 Theme generator ,一個專門用來生成Element主題的工具飒焦。按照文檔,我們生成了需要的主題屿笼。
之后就是我們要做的事情了牺荠,將這個主題的每個元素外面包裹一個class 來做命名空間。
我們這里用到了gulp-css-wrap這個神器驴一,輕輕松松就完成了我們想要的結(jié)果
var path = require('path')
var gulp = require('gulp')
var cleanCSS = require('gulp-clean-css');
var cssWrap = require('gulp-css-wrap');
gulp.task('css-wrap', function() {
return gulp.src( path.resolve('./theme/index.css'))
.pipe(cssWrap({selector:'.custom-theme'}))
.pipe(cleanCSS())
.pipe(gulp.dest('dist'));
});
這樣就得到了一個以.custom-theme為命名空間的自定義主題了休雌,之后我們在項目中引入主題
//main.js
import 'assets/custom-theme/index.css'
我們在換膚的地方toggleClass(document.body, 'custom-theme')
一直toggle body 的 class就可以了。我們就簡單實現(xiàn)了動態(tài)換膚效果肝断。
不過這種模式實現(xiàn)換膚也是有一個弊端的杈曲,它等于把這兩個主題都打包在了項目里,如果你的項目主題需要七八種胸懈,這種模式就不適合了担扑。我們就需要動態(tài)的加載css,下面就是最簡單的動態(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);
側(cè)邊欄
這里又有談一下導(dǎo)航欄的問題洁奈,我項目里的側(cè)邊欄是根據(jù) router.js 配置的路由并且根據(jù)權(quán)限動態(tài)生成的间唉,這樣就省去了寫一遍路由還要再手動寫側(cè)邊欄這種麻煩事绞灼,但也遇到了一個問題利术,路由可能會有多層嵌套,很多人反饋自己的側(cè)邊欄會有三級低矮,甚至還有五級的印叁。所以重構(gòu)了一下側(cè)邊欄,使用了遞歸組件军掂,這樣不管你多少級轮蜕,都能愉快的顯示了。代碼
:default-active="$route.path"
將default-active一直指向當(dāng)前路由就可以了,就是這么簡單终议。
點擊側(cè)邊欄 刷新當(dāng)前路由
在用spa這種開發(fā)模式的之前汇竭,用戶每次點擊側(cè)邊欄都會重新請求這個頁面,用戶漸漸養(yǎng)成了點擊側(cè)邊欄當(dāng)前路由來刷新view的習(xí)慣穴张。但現(xiàn)在spa就不一樣了细燎,用戶點擊當(dāng)前高亮的路由并不會刷新view,因為vue-router會攔截你的路由皂甘,它判斷你的url并沒有任何變化玻驻,所以它不會觸發(fā)任何鉤子或者是view的變化。issue地址偿枕,社區(qū)也對該問題展開了激烈討論璧瞬。
尤大本來也說要增加一個方法來強刷view,但后來他又改變了心意/(ㄒoㄒ)/~~渐夸。但需要就擺在這里彪蓬,我們該怎么辦呢?他說了不改變current URL 就不會觸發(fā)任何東西捺萌,那我可不可以強行觸發(fā)東西你档冬?上有政策, 下有對策我們變著花來hack桃纯。方法也很簡單酷誓,通過不斷改變url的query來觸發(fā)view的變化。我們監(jiān)聽側(cè)邊欄每個link 的 click事件态坦,每次點擊都給router push 一個不一樣的query 來確保會重新刷新view盐数。
clickLink(path) {
this.$router.push({
path,
query: {
t: +new Date() //保證每次點擊路由的query項都是不一樣的,確保會重新刷新view
}
})
}
但這也有一個弊端就是 url 后面有一個很難看的 query 后綴如 xxx.com/article/list?t=1496832345025
伞梯,但我司用戶們表示能接受玫氢。帚屉。。只能暫時這樣hack了漾峡,不知道大家有沒有更好的方法攻旦,學(xué)習(xí)學(xué)習(xí)。
keep-alive
Table
經(jīng)過好幾個版本的迭代生逸,Element 的table組件已經(jīng)能滿足大部分業(yè)務(wù)需求了牢屋。不過rowSpan colSpan表格行/列合并現(xiàn)在并不是支持。官方對此功能的更新情況可以關(guān)注這個issue槽袄。
這里我著重講一下table表格幾個常用的業(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并沒有隨之改變截酷。所以我們就要手動的來管理我們的列表。
this.sortable = Sortable.create(el, {
onEnd: evt => { //監(jiān)聽end事件 手動維護列表
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)編輯也是一個常見的需求。
其實也很簡單歧蕉,當(dāng)我們拿到 list 數(shù)據(jù)之后先洗一下數(shù)據(jù)灾部,每一條數(shù)據(jù)里面插入一個edit[ true or false ]判斷符,來表示當(dāng)前行是否處于編輯狀態(tài)惯退。之后就是通過v-show動態(tài)切換不同的相應(yīng)view就可以了赌髓。完整代碼
<el-table-column min-width="300px" label="標(biāo)題">
<template scope="scope">
<el-input v-show="scope.row.edit" size="small" v-model="scope.row.title"></el-input>
<span v-show="!scope.row.edit">{{ scope.row.title }}</span>
</template>
</el-table-column>
<el-table-column align="center" label="編輯" width="120">
<template scope="scope">
<el-button v-show='!scope.row.edit' type="primary" @click='scope.row.edit=true' size="small" icon="edit">編輯</el-button>
<el-button v-show='scope.row.edit' type="success" @click='scope.row.edit=false' size="small" icon="check">完成</el-button>
</template>
</el-table-column>
Table 常見坑
通過dialog來編輯,新建催跪,刪除table的元素這種業(yè)務(wù)場景相對于前面說的兩種更加的常見锁蠕。而且也有不少的小坑。
首先我們要明確一個點 vue 是一個MVVM框架懊蒸,我們傳統(tǒng)寫代碼是命令式編程荣倾,拿到table這個dom之后就是命令式對dom增刪改。而我們現(xiàn)在用聲明式編程骑丸,只用關(guān)注data的變化就好了舌仍,所以我們這里的增刪改都是基于list這個數(shù)組來的。這里我們還要明確一點vue 列表渲染注意事項
由于 JavaScript 的限制通危, Vue 不能檢測以下變動的數(shù)組:
* 當(dāng)你利用索引直接設(shè)置一個項時铸豁,例如: vm.items[indexOfItem] = newValue
所以我們想改變table中第一條數(shù)據(jù)的值,通過this.list[0]=newValue
這樣是不會生效的菊碟。
解決方案:
// Array.prototype.splice`
example1.items.splice(indexOfItem, 1, newValue)
所以我們可以通過
//添加數(shù)據(jù)
this.list.unshift(this.temp);
//刪除數(shù)據(jù)
const index = this.list.indexOf(row); //找到要刪除數(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ā)視圖更新
這樣我們就完成了對table的增刪改操作节芥,列表view也自動響應(yīng)發(fā)生了變化。這里在修改數(shù)據(jù)的時候還有一個小坑需要主要。
當(dāng)我們拿到需要修改行的數(shù)據(jù)時候不能直接將它直接賦值給dialog头镊,不然會發(fā)生下面的問題蚣驼。
如上圖所示,我們在dialog里面改變狀態(tài)的時候相艇,遮罩下面的table里面該行的狀態(tài)也在那里跟著一只變化著颖杏。原因想必大家都猜到了。賦值的數(shù)據(jù)是一個objec引用類型共享一個內(nèi)存區(qū)域的厂捞。所以我們就不能直接連等復(fù)制输玷,需要重新指向一個新的引用队丝,方案如下:
//賦值對象是一個obj
this.objData=Object.assign({}, row) //這樣就不會共用同一個對象
//數(shù)組我們也有一個巧妙的防范
newArray = oldArray.slice(); //slice會clone返回一個新數(shù)組
Tabs
tab在后臺項目中也比較常用的靡馁。假設(shè)我們有四個tab選項,每個tab都會向后端請求數(shù)據(jù)机久,但我們希望一開始只會請求當(dāng)前的tab數(shù)據(jù)臭墨,而且tab來回切換的時候不會重復(fù)請求,只會實例化一次膘盖。首先我們想到的就是用v-if
這樣的確能做到一開始不會掛載后面的tab胧弛,但有一個問題,每次點擊這個tab組件都會重新掛載一次侠畔,這是我們不想看到的结缚,這時候我們就可以用到<keep-alive>
了。
keep-alive 包裹動態(tài)組件時软棺,會緩存不活動的組件實例红竭,而不是銷毀它們。 它是一個抽象組件:它自身不會渲染一個 DOM 元素喘落,也不會出現(xiàn)在父組件鏈中茵宪。
所以我們就可以這樣寫tabs了
<el-tabs v-model="activeTab">
<el-tab-pane label="簡介及公告" name="announcement">
<announcement />
</el-tab-pane>
<el-tab-pane label="資訊" name="information">
<keep-alive>
<information v-if="activeTab=='information'" />
</keep-alive>
</el-tab-pane>
<el-tab-pane label="直播流配置" name="stream">
<keep-alive>
<stream v-if="activeTab=='stream'" />
</keep-alive>
</el-tab-pane>
</el-tabs>
Select 選擇器
Select 選擇器直接使用沒有什么太多問題,但很多時候我們需要通過Select來回顯一些數(shù)據(jù)瘦棋,當(dāng)我們<el-select v-model="objValue">
select 綁定一個obj value回顯就會很蛋疼了稀火,它要求必須保持同一個引用issue。這就意味著赌朋,我們回顯數(shù)據(jù)的時候想先要找到該數(shù)據(jù)在arr中的位置凰狞,再回塞:demo。這還不是在遠(yuǎn)程搜索的情況下沛慢,如果是遠(yuǎn)程搜索的情況還要當(dāng)疼赡若。
這里推薦一下vue-multiselect 它能完美的解決前面Element select的問題。目前也是vue component 中比較好用的一個颠焦,ui也非常的好看斩熊,建議大家可以嘗試性用一下,真的非常的不錯伐庭。
Upload 上傳
Upload本身沒什么好說的粉渠,文檔寫的蠻清楚了分冈。這里主要說一下怎么將Upload組件和七牛直傳結(jié)合在一起。
這里我們選擇api直傳的方式霸株,就是我們首先要通過后端(go,node,php都可以)文檔生成七牛上傳必要的token(上傳憑證)和key(資源的最終名稱)雕沉。
所以現(xiàn)在只要想辦法講token和key塞進post請求里面就可以了,好在官方也提供了這個方法去件。
坡椒。但怎么才能先異步的拿到token再將它塞入請求里呢?
這時候我們又發(fā)現(xiàn)了before-upload 這個鉤子還支持promise簡直合我們的心意尤溜。
但我們寫著寫著怎樣才能動態(tài)的改變之前的dataObj呢倔叼?通過看源碼發(fā)現(xiàn)我們可以_self._data這樣子拿到我們想要的數(shù)據(jù)。線上代碼
<template>
<el-upload
action="https://upload.qbox.me"
:data="dataObj"
drag
:multiple="true"
:before-upload="beforeUpload">
<i class="el-icon-upload"></i>
<div class="el-upload__text">將文件拖到此處宫莱,或<em>點擊上傳</em></div>
</el-upload>
</template>
<script>
import { getToken } from 'api/qiniu'; // 獲取七牛token 后端通過Access Key,Secret Key,bucket等生成token
// 七牛官方sdk https://developer.qiniu.com/sdk#official-sdk
export default{
data() {
return {
dataObj: { token: '', key: '' },
image_uri: [],
fileList: []
}
},
methods: {
beforeUpload() {
const _self = this;
return new Promise((resolve, reject) => {
getToken().then(response => {
const key = response.data.qiniu_key;
const token = response.data.qiniu_token;
_self._data.dataObj.token = token;
_self._data.dataObj.key = key;
resolve(true);
}).catch(err => {
console.log(err)
reject(false)
});
});
}
}
}
</script>
jsx
在使用Element的時候丈攒,官方提供了很多可以自己寫render function的地方,但由于Element內(nèi)部都是用jsx 寫render function的授霸,所以demo也都是jsx巡验,但很多人自己項目中其實是沒有安裝的,導(dǎo)致報錯碘耳。但說真的用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ā)問題:一直有人在群里問<el-input @click="handlenClick">Click Me</el-input>
怎么不觸發(fā)click事件捕捂,雖然element文檔還有完善的空間但這種問題大家還真要自己好好認(rèn)真看一下官方的FAQ了。
官方說明了所有的原生事件必須添加 .native 修飾符愉阎。
修改element樣式問題: 用ui組件總免不了需要對它做一些個性化定制的需求绞蹦,所以我們就要覆蓋element的一些樣式。
首先我們要了解一下vue scoped是什么榜旦,很多人非常喜歡用scoped幽七,媽媽再也不用擔(dān)心樣式?jīng)_突問題了,其實scoped也沒有很神秘的溅呢,它就是基于PostCss的澡屡,加了一個作用局的概念。
//編譯前
.example {
color: red;
}
//編譯后
.example[_v-f3f3eg9] {
color: red;
}
它和我們傳統(tǒng)的命名空間的方法避免css沖突沒有什么本質(zhì)性的區(qū)別咐旧。
現(xiàn)在我們來說說怎么覆蓋element-ui樣式驶鹉。由于element-ui的樣式我們是在全局引入的,所以你想在某個view里面覆蓋它的樣式就不能加scoped铣墨,但你又想只覆蓋這個頁面的element樣式室埋,你就可在它的父級加一個class,以用命名空間來解決問題。
.aritle-page{ //你的命名空間
.el-tag { //element-ui 元素
margin-right: 0px;
}
}
建議向樓主一樣專門建一個scss文件里專門自定義element-ui的各種樣式姚淆。線上代碼
其它關(guān)于element相關(guān)的東西真的沒有什么好說的了孕蝉,人家文檔和源碼就放在那里,有問題就去看文檔腌逢,再去issue里找找降淮,再去看看源碼,大部分問題都能解決了搏讶。給一個訣竅其實大部分詭異的問題都可以通過加一個key或者
Vue.nextTick來解決佳鳖。。
富文本
管理后臺富文本也是一個非常重要的功能媒惕,樓主在這里也踩了不少的坑系吩。樓主在項目里最終選擇了tinymce
這里在簡述一下推薦使用tinymce的原因:tinymce是一家老牌做富文本的公司(這里也推薦ckeditor,也是一家一直做富文本的公司吓笙,也不錯)淑玫,它的產(chǎn)品經(jīng)受了市場的認(rèn)可巾腕,不管是文檔還是配置的自由度都很好面睛。在使用富文本的時候有一點也很關(guān)鍵就是復(fù)制格式化,之前在用一款韓國人做的富文本summernote被它的格式化坑的死去活來尊搬,但tinymce的去格式化相當(dāng)?shù)暮萌€有一個增值項目就是powerpaste,那是無比的強大,支持從word里面復(fù)制各種東西佛寿,都不會有問題幌墓。富文本還有一點也很關(guān)鍵,就是拓展性冀泻。樓主用tinymce寫了好幾個插件常侣,學(xué)習(xí)成本和容易度都不錯,很方便拓展弹渔。最后一點就是文檔很完善胳施,基本你想得到的配置項,它都有肢专。tinymce也支持按需加載舞肆,你可以通過它官方的build頁定制自己需要的plugins。
我再來分析一下市面上其它的一些富文本:
- summernote 先來說一個我絕對不推薦的富文本博杖。這是一個韓國人開源的富文本(當(dāng)然不推薦的理由不是因為這個_)椿胯,它對很多富文本業(yè)界公認(rèn)的默認(rèn)行為理解是反起到而行的,而且只用了一個dialog的功能剃根,引入了boostrap哩盲,一堆人抗議就是不改。格式化也是懶得一批。廉油。反正不要用镣丑!不要用!不要用娱两!
- ckeditor ckeditor也是一家老牌做富文本的公司莺匠,樓主舊版后臺用的就是這個,今年也出了4.0版本十兢,ui也變美觀了不少趣竣,相當(dāng)?shù)牟诲e,而且它號稱是插件最豐富的富文本了旱物。推薦大家也可以試用一下遥缕。
- quill 也是一個非常火的富文本宵呛,長相很不錯单匣。基于它寫插件也很簡單宝穗,api設(shè)計也很簡單户秤。樓主不選擇它的原因是它對圖片的各種操作不友善,而且很難改逮矛。如果對圖片沒什么操作的用戶鸡号,推薦使用。
- medium-editor 大名鼎鼎的medium的富文本(非官方出品)须鼎,但完成度還是不很不錯鲸伴,拓展性也不錯。不過我覺得大部分用戶還是會不習(xí)慣medium這種寫作方式的晋控。
- Squire 一個比較輕量的富文本汞窗,壓縮完才11.5kb,相對于其它的富文本來說是非常的小了赡译,推薦功能不復(fù)雜的建議使用仲吏。
- wangEditor 一個國人寫的富文本,用過感覺還是不錯的捶朵。不過畢竟是個人的蜘矢,不像專門公司做富文本的,配置型和豐富性不足综看。前端幾大禁忌就有富文本 為什么都說富文本編輯器是天坑?品腹,不過個人能做成這樣子很不容易了。
- 百度UEditor 沒有深入使用過红碑,只在一個angular1X的項目簡單用過舞吭,不過說著的ui真的不好看泡垃,不符合當(dāng)今審美了,官方也已經(jīng)很久沒跟新過了羡鸥。
樓主列舉了很多富文本但并沒有列舉任何vue相關(guān)的富文本蔑穴,主要是因為富文本真的比想象中復(fù)雜,在前面的文章里也說過了惧浴,其實用vue封裝組件很方便的存和,沒必要去用人家封裝的東西什么vue-quill vue-editor這種都只是簡單包了一層,沒什么難度的衷旅。還不如自己來封裝捐腿,靈活性可控性更強一點。還有一點基于vue真沒什么好的富文本柿顶,不像 react 有facebook 出的draft-js茄袖,ory出的editor,這種大廠出的產(chǎn)品嘁锯。
Markdown
markdown 我們這里選用了 simplemde-markdown-editor 宪祥,簡單的用vue封裝了一下地址,如果需求方能接受 markdown 就一定要用 markdown,坑真心會比富文本少很多家乘。這里我們用markdown做了編輯器蝗羊,還需要一個能解析的的東西】镜停可以你傳給后端讓后端幫你轉(zhuǎn)化肘交,也可以前端自己來,這里推薦一個轉(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)然它還有很多個性畫的配置凉驻,大家有需求自行研究吧腻要。
導(dǎo)出excel
這里先明確一點,如果你的業(yè)務(wù)需求對導(dǎo)出文件的格式?jīng)]有什么要求涝登,不建議導(dǎo)出成xlsx格式的雄家,直接導(dǎo)出成csv的就好了,真的會簡單很多胀滚。創(chuàng)建一個a標(biāo)簽趟济,寫上data:text/csv;charset=utf-8
頭,再把數(shù)據(jù)塞進去咽笼,encodeURI(csvContent)
一下就好了顷编,詳情就不展開了,大家可以借鑒這個stackoverflow回答剑刑。
我們重點說一下轉(zhuǎn)xlsx媳纬,我們這里用到了js-xlsx双肤,一個功能很強大excel處理庫,只是下載各種格式excel钮惠,還支持讀取excel茅糜,但上手難度也非常大,相當(dāng)?shù)膹?fù)雜素挽,其中涉及不少二進制相關(guān)的東西蔑赘。不過好在官方給了我們一個demo例子,我們寫不來還抄不來么,于是我們就借鑒官方的例子來改造了一下预明,具體原理就不詳細(xì)說了米死,真的很復(fù)雜央碟。碉碉。。
重點是我們怎么使用锄列!首先我們封裝一個Export2Excel.js窗慎,
它又依賴三個庫
require('script-loader!file-saver'); //保存文件用
require('script-loader!vendor/Blob'); //轉(zhuǎn)二進制用
require('script-loader!xlsx/dist/xlsx.core.min'); //xlsx核心
由于這幾個文件不支持import引入物喷,所以我們需要`script-loader`來將他們掛載到全局環(huán)境下。
它暴露了兩個接口export_table_to_excel
和export_json_to_excel
,我們常用export_json_to_excel
因為更加的可控一點遮斥,我們可以自由的洗數(shù)據(jù)峦失。
handleDownload() {
require.ensure([], () => { // 用 webpack Code Splitting xlsl還是很大的
const { export_json_to_excel } = require('vendor/Export2Excel');
const tHeader = ['序號', '文章標(biāo)題', '作者', '閱讀數(shù)', '發(fā)布時間']; // excel 表格頭
const filterVal = ['id', 'title', 'author', 'pageviews', 'display_time'];
const list = this.list;
const data = this.formatJson(filterVal, list); // 自行洗數(shù)據(jù) 按序排序的一個array數(shù)組
export_json_to_excel(tHeader, data, '列表excel');
})
},
formatJson(filterVal, jsonData) {
return jsonData.map(v => filterVal.map(j => v[j]))
}
ECharts
管理后臺圖表也是常見得需求术吗。這里圖表就只推薦ECharts尉辑,功能齊全,社區(qū)demo也豐富gallery较屿。我還是那個觀點隧魄,大部分插件建議大家還是自己用vue來包裝就好了,真的很簡單隘蝎。ECharts支持webpack引入购啄,圖省事可以將ECharts整個引入var echarts = require('echarts');
不過ECharts還是不小的,我們大部分情況只是用到很少一部分功能嘱么,我平時習(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了。因為ECharts初始化必須綁定dom曼振,所以我們只能在vue的mounted生命周期里初始化几迄。
mounted() {
this.initCharts();
},
methods: {
initBar() {
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就配置完成了冰评,這時候你想說我的data是遠(yuǎn)程獲取的映胁,或者說我動態(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ù)變化時觸發(fā)ECharts
watch: {
seriesData(val) {
this.setOptions({series:val})
}
}
其實都差不多屿愚,還是要結(jié)合自己業(yè)務(wù)來封裝汇跨。后面就和平時使用ECharts沒有什么區(qū)別了。題外話ECharts的可配置項真心多妆距,大家使用的時候可能要花一點時間了解它的api的穷遂。知乎有個問題:百度還有什么比較良心的產(chǎn)品?答案:ECharts娱据,可見ECharts的強大與好用蚪黑。
相同component 不同參數(shù)
創(chuàng)建與編輯
其實后臺創(chuàng)建與編輯功能是最常見的了,它區(qū)別去前臺項目多了改的需求中剩,但大部分創(chuàng)建頁面與編輯頁面字段和ui幾乎是一樣的忌穿,所以我們準(zhǔn)備公用一個component來對應(yīng)不同的頁面。有兩種常見的方法结啼,來區(qū)別創(chuàng)建與編輯掠剑。
- 通過路由path的方式
這種方式最簡單暴力,我自己的項目中使用這種方式郊愧,通過約定路徑中出現(xiàn)'edit'就判斷為編輯模式朴译。比較省力和方便,不過這是要在大家寫路徑的時候都按照規(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();
}
},
就這樣簡單的實現(xiàn)了多路由復(fù)用了一個component焦蘑,其實不只是創(chuàng)建和編輯可以這樣用盯拱,如兩個列表的一模一樣,只是一個是內(nèi)部文章另一個是調(diào)取外部文章都能復(fù)用組件例嘱,通過meta的方式來判斷調(diào)取不同的接口狡逢。
占坑
常規(guī)占坑,這里是手摸手蝶防,帶你用vue擼后臺系類
完整項目地址:vue-element-admin
系類文章一:手摸手甚侣,帶你用vue擼后臺 系列一(基礎(chǔ)篇)
系類文章二:手摸手,帶你用vue擼后臺 系列二(登錄權(quán)限篇)
之后計劃項目應(yīng)會加上i18n间学,并完善一下代碼和文檔。
下一篇文章可能會寫關(guān)于如何用 electron 包裝現(xiàn)有項目印荔,快速實現(xiàn)一個跨平臺的終端后臺低葫。
相應(yīng)廣大需求 建了一個qq群 591724180 方便大家交流