項目源碼地址在文檔最後css
定義多個子組件,在父組件中引用
如圖,紅框中index.vue爲父組件,上面文件夾均爲子組件。
html
在父組件中引用並註冊子組件
vue
經過currentRole控制展現哪一個組件
node
如圖,在父組件中引入子組件並在中放內容
git
剛纔放置的內容將在子組件的slot標籤位置展現。
github
結果如圖:
關於插槽還有不少應用,具體請參考:https://www.cnblogs.com/lovey...vue-router
完整url: window.location.href 路由路徑: this.$route.path 路由路徑參數: this.$route.params
定義好路由信息
express
左側導航欄部分代碼以下:npm
<el-menu class="el-menu-vertical-demo" background-color="#545c64" text-color="rgb(191, 203, 217)" router unique-opened active-text-color="rgb(64, 158, 255)" :default-active="$route.path" @open="handleOpen" @close="handleClose"> <template v-for="(item,index) in $router.options.routes" v-key='item.path'> <el-submenu :index="index+''" v-if="!item.leaf"> <template slot="title"><i :class="'iconfont '+item.icon"></i>{{item.name}}</template> <el-menu-item v-for='(child,index) in item.children' :index='child.path' :key='index'> <template slot="title"> <span>{{child.name}}</span> </template> </el-menu-item> </el-submenu> <el-menu-item :index='item.children[0].path' v-if="item.leaf"> <template slot="title"> <i :class="'iconfont '+item.icon"></i> <span>{{item.name}}</span> </template> </el-menu-item> </template> </el-menu>
解析:遍歷所有路由信息 $router.options.routes,經過leaf值判斷是否有二級菜單。有二級菜單需用el-submenu。element-ui
效果圖以下:
el-menu增長collapse
屬性,經過控制該值控制導航欄展開收起。
經過點擊圖標控制isCollapse。左側導航欄收起時 右側寬度也需改變,因此此項目選用flex佈局,右側設置樣式flex:1
需增長樣式
.el-menu-vertical-demo:not(.el-menu--collapse) { width: 200px; }
效果圖以下:
nprogress
安裝:npm install \--save nprogress
使用:
//route.js //導入 import NProgress from 'nprogress' import 'nprogress/nprogress.css' router.beforeEach((to, from, next) => { NProgress.start() next() }) router.afterEach(() => { NProgress.done() })
效果圖:
可手動修改顏色:
#nprogress .bar { background: red !important; //自定義顏色 }
screenfull
實現全屏操做並監聽ESC安裝 npm install --save screenfull
引入 import screenfull from 'screenfull'
經過fullFlag展現當前狀態(展開/收起)
full方法實現全屏:
full:function(){ if (!screenfull.isEnabled) { // 若是不容許進入全屏,發出不容許提示 this.$message({ message: '不支持全屏', type: 'warning' }) return false } this.fullFlag=!this.fullFlag screenfull.toggle(); },
當點擊ESC退出全屏時,需改變當前狀態(即收起要變成展開),這裏經過監聽瀏覽器大小變化結合screenfull.isFullscreen
實現
mounted(){ let me=this; window.onresize=function(){ // 全屏下監控是否按鍵了ESC if (!me.checkFull()) { // 全屏下按鍵esc後要執行的動做 me.fullFlag = false } } },
checkFull方法以下:
checkFull() { var isFull = screenfull.isFullscreen; if (isFull === undefined) { isFull = false; } return isFull; }
全屏狀態實現效果:
el-dialog
及自定義標題自定義標題:
經過dialogVisible
值控制彈框展現/隱藏:
<el-dialog title="提示" :visible.sync="dialogVisible" width="30%" v-dialogDrag> <div slot="title" class="header-title"> <span class="title-name"> <i class='iconfont iconapplications'></i> 自定義標題 </span> </div> <span>這是一段信息</span> <span slot="footer" class="dialog-footer"> <el-button @click="dialogVisible = false" size='mini'>取 消</el-button> <el-button type="primary" @click="dialogVisible = false" size='mini'>確 定</el-button> </span> </el-dialog>
Vue.directive
自定義指令實現可拖動的彈框el-dialog
咱們先來講說Vue.directive
Vue.directive:自定義指令,相似內置的v-if,v-show。便可根據本身需求增長指令。
來看下官網的案例:
需求:實如今打開頁面後還沒點擊過任何內容,這個輸入框就處於聚焦狀態。
// 註冊一個全局自定義指令 `v-focus` Vue.directive('focus', { // 當被綁定的元素插入到 DOM 中時…… inserted: function (el) { // 聚焦元素 el.focus() } })
再來介紹下他的鉤子函數:
一個指令定義對象能夠提供以下幾個鉤子函數 (均爲可選):
bind
:只調用一次,指令第一次綁定到元素時調用。在這裏能夠進行一次性的初始化設置。inserted
:被綁定元素插入父節點時調用 (僅保證父節點存在,但不必定已被插入文檔中)。update
:所在組件的 VNode 更新時調用,可是可能發生在其子 VNode 更新以前。指令的值可能發生了改變,也可能沒有。可是你能夠經過比較更新先後的值來忽略沒必要要的模板更新 (詳細的鉤子函數參數見下)。componentUpdated
:指令所在組件的 VNode及其子 VNode所有更新後調用。unbind
:只調用一次,指令與元素解綁時調用。接下來咱們來看一下鉤子函數的參數 (即el
、binding
、vnode
和oldVnode
)。
指令鉤子函數會被傳入如下參數:
鉤子函數參數:
el
:指令所綁定的元素,能夠用來直接操做 DOM。binding
:一個對象,包含如下 property:
name
:指令名,不包括v-
前綴。value
:指令的綁定值,例如:v-my-directive="1 + 1"
中,綁定值爲2
。oldValue
:指令綁定的前一個值,僅在update
和componentUpdated
鉤子中可用。不管值是否改變均可用。expression
:字符串形式的指令表達式。例如v-my-directive="1 + 1"
中,表達式爲"1 + 1"
。arg
:傳給指令的參數,可選。例如v-my-directive:foo
中,參數爲"foo"
。modifiers
:一個包含修飾符的對象。例如:v-my-directive.foo.bar
中,修飾符對象爲{ foo: true, bar: true }
。vnode
:Vue 編譯生成的虛擬節點。移步VNode API來了解更多詳情。oldVnode
:上一個虛擬節點,僅在update
和componentUpdated
鉤子中可用。除了el
以外,其它參數都應該是隻讀的,切勿進行修改。若是須要在鉤子之間共享數據,建議經過元素的dataset
來進行。
具體請看官網:https://cn.vuejs.org/v2/guide...
接下來實現彈框的拖拽:
main.js中定義:
//main.js Vue.directive('dialogDrag', { bind(el, binding, vnode, oldVnode) { const dialogHeaderEl = el.querySelector('.el-dialog__header') const dragDom = el.querySelector('.el-dialog') dialogHeaderEl.style.cursor = 'move' // 獲取原有屬性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null); const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null) dialogHeaderEl.onmousedown = (e) => { // 鼠標按下,計算當前元素距離可視區的距離 const disX = e.clientX - dialogHeaderEl.offsetLeft; const disY = e.clientY - dialogHeaderEl.offsetTop; const screenWidth = document.body.clientWidth; const screenHeight = document.body.clientHeight; const minDragDomLeft = dragDom.offsetLeft; const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDom.offsetWidth; const minDragDomTop = dragDom.offsetTop; const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDom.offsetHeight; // 獲取到的值帶px 正則匹配替換 let styL, styT // 注意在ie中 第一次獲取到的值爲組件自帶50% 移動以後賦值爲px if (sty.left.includes('%')) { styL = +screenWidth * (+sty.left.replace(/\%/g, '') / 100) styT = +screenHeight * (+sty.top.replace(/\%/g, '') / 100) } else { styL = +sty.left.replace(/\px/g, '') styT = +sty.top.replace(/\px/g, '') } document.onmousemove = function(e) { // 經過事件委託,計算移動的距離 var l = e.clientX - disX; var t = e.clientY - disY; // 邊界處理 if (-(l) > minDragDomLeft) { l = -minDragDomLeft } else if (l > maxDragDomLeft) { l = maxDragDomLeft } if (-(t) > minDragDomTop) { t = -minDragDomTop } else if (t > maxDragDomTop) { t = maxDragDomTop } // 移動當前元素 dragDom.style.left = `${l + styL}px` dragDom.style.top = `${t + styT}px` } document.onmouseup = function(e) { document.onmousemove = null document.onmouseup = null } } } })
dialog中增長該屬性,就能夠實現啦。
基於上面的自定義拖拽方法,畫了個簡圖以便理解(top同理):
router.beforeEach
結合addRouters
實現根據用戶權限控制路由(導航欄)先來簡單介紹下router.beforeEach
導航守衛
當一個導航觸發時,全局前置守衛按照建立順序調用。守衛是異步解析執行,此時導航在全部守衛 resolve 完以前一直處於等待中。
每一個守衛方法接收三個參數:
to: Route
: 即將要進入的目標from: Route
: 當前導航正要離開的路由next: Function
: 必定要調用該方法來resolve這個鉤子。執行效果依賴next
方法的調用參數。
next()
: 進行管道中的下一個鉤子。若是所有鉤子執行完了,則導航的狀態就是confirmed(確認的)。next(false)
: 中斷當前的導航。若是瀏覽器的 URL 改變了 (多是用戶手動或者瀏覽器後退按鈕),那麼 URL 地址會重置到from
路由對應的地址。next('/')
或者next({ path: '/' })
: 跳轉到一個不一樣的地址。當前的導航被中斷,而後進行一個新的導航。你能夠向next
傳遞任意位置對象,且容許設置諸如replace: true
、name: 'home'
之類的選項以及任何用在router-link的toprop中的選項。next(error)
: (2.4.0+) 若是傳入next
的參數是一個Error
實例,則導航會被終止且該錯誤會被傳遞給router.onError()註冊過的回調。確保要調用next
方法,不然鉤子就不會被 resolved。
好吧 我攤牌了 我是從官網複製來的,想看更多歡迎去官網:https://router.vuejs.org/zh/g...
接下來咱們來看看具體如何實現:
定義路由的文件中分紅幾個數組
圖中constantRoutes
爲全部用戶均可以訪問的路由,adminRoutes
爲用戶名爲‘admin’登陸才能夠訪問的路由。
先賦值當前能夠訪問的路由:
const router = new Router({ routes: constantRoutes, }); export default router;
登陸時,在session裏存入用戶名,用來判斷是否已登陸及用戶名
login:function(){ let me=this; me.$refs.ruleForm.validate((valid) => { if (valid) { sessionStorage.setItem('user',me.loginForm.user); if(sessionStorage.getItem('user')){ me.$router.push({path:"/index"}) } } }) }
main.js中控制路由
let flag=false;//此字段用來防止刷新時重複添加路由 router.beforeEach((to, from, next) => { NProgress.start() let user=sessionStorage.getItem('user'); if(to.path=='/login'){//用來防止一直跳入login,進入死循環 next(); } //判斷是否登陸了,固然真實項目判斷權限不會這麼簡單,此案例只提供思路及基本使用 if(user){ if(to.path=='/login'){ next('/');//登陸後在想跳入login時直接跳入首頁 } if(flag){ next(); } else { let routes=[]; if(user=='admin'){//判斷爲管理員 routes=adminRoutes; router.addRoutes(routes);//添加管理員的路由信息 router.options.routes = router.options.routes.concat(routes); //因爲addRoutes只會註冊路由表,並無更新router.options.routes的數據 } flag=true; next({...to, replace: true}); } } else { if(to.path!='/login'){ next('/login'); } NProgress.done() } })
成果:當沒有登錄時會強制跳轉至登陸頁,登陸後用戶名爲admin
時展現:
當不爲admin時:
//經過控制type屬性實現控制密碼的展現隱藏 <el-form-item label="" prop="password"> <el-input placeholder="請輸入密碼" v-model="loginForm.password" :type="passwordType" auto-complete="new-password"> <i slot="prefix" class="iconfont iconmima"></i> <i slot="suffix" class="iconfont iconbiyan pointer" @click='passwordType=""' v-if='passwordType=="password"'></i> <i slot="suffix" class="iconfont iconeye pointer" @click='passwordType="password"' v-else></i> </el-input> </el-form-item>
實現效果:
使用element的el-dropdown
<el-dropdown class='avaImg' trigger="click"> //trigger 設置下拉框展現觸發方式,默認爲觸摸展現 <span class="el-dropdown-link"> <img src="../assets/img.png" alt=""> <div> <i class="iconfont iconxiala" style='padding:0 5px;font-size:15px;'></i> </div> </span> <el-dropdown-menu slot="dropdown" > <el-dropdown-item> <span @click='logOut'>登出</span> </el-dropdown-item> </el-dropdown-menu> </el-dropdown>
登出方法:
logOut:function(){ let me=this; this.$confirm('確認要登出嗎?', '提示', { confirmButtonText: '肯定', cancelButtonText: '取消', type: 'warning' }).then(() => { sessionStorage.setItem('user',''); me.$router.push('/login'); window.location.reload();//更新main.js的flag值,從新根據角色獲取路由 }).catch(() => { }); }
實現效果:
breadcrumb
實現展現麪包屑<transition mode="out-in"> <el-breadcrumb separator="/"> <el-breadcrumb-item :to="{ path: '/index' }">首頁</el-breadcrumb-item> <el-breadcrumb-item v-for='item in breadcrumb' :key='item.name'>{{item.name}}</el-breadcrumb-item> </el-breadcrumb> </transition>
監聽路由變化實時更新(進入界面也要初始化,方法同):
watch: { $route(route) { let match=route.matched; match=match.filter(item => item.name&&item.name!='首頁' ); this.breadcrumb=match; } }
效果圖:
clipboard
實現文本複製實現步驟:
安裝clipboard
npm install clipboard --save
初始化
import Clipboard from 'clipboard' var clipboard = new Clipboard('.btn');
<el-input id="foo" placeholder="請輸入內容" v-model="ipt"> <el-tooltip class="item" effect="dark" content="點我複製哦" placement="top" slot="append"> <el-button class="btn" data-clipboard-target="#foo"> <i class='iconfont iconfuzhi'></i> </el-button> </el-tooltip> </el-input>
定義回調函數
clipboard.on('success', function(e) { me.$message({ message: '複製成功', type: 'success' }); e.clearSelection(); }); clipboard.on('error', function(e) { me.$message({ message: '複製失敗', type: 'success' }); });
實現效果:
詳細請看:http://www.clipboardjs.cn/
源碼地址:https://github.com/myweiwei/vue-
將不斷更新完善,期待您的批評指正!