vue項目中乾貨 不斷完善中...

項目源碼地址在文檔最後css

1.關於根據權限展現不一樣界面的實現

定義多個子組件,在父組件中引用
如圖,紅框中index.vue爲父組件,上面文件夾均爲子組件。
image.pnghtml

在父組件中引用並註冊子組件
image.pngvue

經過currentRole控制展現哪一個組件
image.pngnode

2.插槽 slot
  • 插槽(Slot)是Vue提出來的一個概念,正如名字同樣,插槽用於決定將所攜帶的內容,插入到指定的某個位置,從而使模板分塊,具備模塊化的特質和更大的重用性。
  • 插槽顯不顯示、怎樣顯示是由父組件來控制的,而插槽在哪裏顯示就由子組件來進行控制

如圖,在父組件中引入子組件並在中放內容
image.pnggit

剛纔放置的內容將在子組件的slot標籤位置展現。
image.pnggithub

結果如圖:
image.png
關於插槽還有不少應用,具體請參考:https://www.cnblogs.com/lovey...vue-router

3.獲取當前頁面路由信息
完整url: window.location.href
路由路徑: this.$route.path
路由路徑參數: this.$route.params
4.結合element-ui實現左側導航欄

定義好路由信息
image.pngexpress

  • icon爲對應圖標
  • leaf判斷是否有二級菜單。爲true表示沒有

左側導航欄部分代碼以下: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 : 是否使用 vue-router 的模式,啓用該模式會在激活導航時以 index 做爲 path 進行路由跳轉
  • unique-opened : 是否只保持一個子菜單的展開
  • default-active : 默認高亮菜單

解析:遍歷所有路由信息 $router.options.routes,經過leaf值判斷是否有二級菜單。有二級菜單需用el-submenuelement-ui

效果圖以下:
image.png

5.導航欄增長展開收起功能

el-menu增長collapse屬性,經過控制該值控制導航欄展開收起。
image.png
經過點擊圖標控制isCollapse。左側導航欄收起時 右側寬度也需改變,因此此項目選用flex佈局,右側設置樣式flex:1
image.png
需增長樣式

.el-menu-vertical-demo:not(.el-menu--collapse) {
        width: 200px;
  }

效果圖以下:
image.png

6.瀏覽器頂部進度條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()
})

效果圖:
image.png

可手動修改顏色:

#nprogress  .bar  { 
    background: red !important; //自定義顏色 
 }
7.screenfull實現全屏操做並監聽ESC

安裝 npm install --save screenfull
引入 import screenfull from 'screenfull'

經過fullFlag展現當前狀態(展開/收起)
image.png

full方法實現全屏:

full:function(){
    if (!screenfull.isEnabled) { // 若是不容許進入全屏,發出不容許提示
        this.$message({
            message: '不支持全屏',
            type: 'warning'
        })
        return false
    }
    this.fullFlag=!this.fullFlag
    screenfull.toggle();
},

當點擊ESC退出全屏時,需改變當前狀態(即收起要變成展開),這裏經過監聽瀏覽器大小變化結合screenfull.isFullscreen實現
image.png

mounted(){
      let me=this;
      window.onresize=function(){
        // 全屏下監控是否按鍵了ESC
        if (!me.checkFull()) {
        // 全屏下按鍵esc後要執行的動做
            me.fullFlag = false
        }
      }
  },

checkFull方法以下:
image.png

checkFull() {
        var isFull = screenfull.isFullscreen;
        if (isFull === undefined) {
            isFull = false;
        }
        return isFull;
    }

全屏狀態實現效果:

image.png

8.關於彈框el-dialog及自定義標題

自定義標題:
image.png

經過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>
9.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:只調用一次,指令與元素解綁時調用。

接下來咱們來看一下鉤子函數的參數 (即elbindingvnodeoldVnode)。
指令鉤子函數會被傳入如下參數:
鉤子函數參數:

  • el:指令所綁定的元素,能夠用來直接操做 DOM。
  • binding:一個對象,包含如下 property:

    • name:指令名,不包括v-前綴。
    • value:指令的綁定值,例如:v-my-directive="1 + 1"中,綁定值爲2
    • oldValue:指令綁定的前一個值,僅在updatecomponentUpdated鉤子中可用。不管值是否改變均可用。
    • 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:上一個虛擬節點,僅在updatecomponentUpdated鉤子中可用。

除了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中增長該屬性,就能夠實現啦。
image.png

基於上面的自定義拖拽方法,畫了個簡圖以便理解(top同理):
未命名文件.png

10.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: truename: 'home'之類的選項以及任何用在router-link的toprop中的選項。
    • next(error): (2.4.0+) 若是傳入next的參數是一個Error實例,則導航會被終止且該錯誤會被傳遞給router.onError()註冊過的回調。

確保要調用next方法,不然鉤子就不會被 resolved。
好吧 我攤牌了 我是從官網複製來的,想看更多歡迎去官網:https://router.vuejs.org/zh/g...

接下來咱們來看看具體如何實現:

定義路由的文件中分紅幾個數組
圖中constantRoutes爲全部用戶均可以訪問的路由,adminRoutes爲用戶名爲‘admin’登陸才能夠訪問的路由。
image.png
先賦值當前能夠訪問的路由:

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時展現:
image.png
image.png

當不爲admin時:
image.png

11.密碼的顯示隱藏
//經過控制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>

實現效果:
image.png

image.png

12.登出功能

使用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(() => {
    });
}

實現效果:
image.png

13.結合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;
    }
  }

效果圖:
image.png

14.結合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'
    });
});

實現效果:
image.png
詳細請看:http://www.clipboardjs.cn/

源碼地址:https://github.com/myweiwei/vue-
將不斷更新完善,期待您的批評指正!

相關文章
相關標籤/搜索