Vue 2.x 實戰(zhàn)之后臺管理系統(tǒng)開發(fā)(二)

1. 導語

承接上文:Vue 2.x 實戰(zhàn)之后臺管理系統(tǒng)開發(fā)(一)

在上一篇文章中沾谜,我詳細敘述了如何創(chuàng)建項目框架和引入各種后臺常用插件伶授,做好這些準備工作后涮因,我們就可以著手進行頁面的開發(fā)了拒迅。在開發(fā)過程中沥寥,會遇到一些常見的需求和問題颤练,我整理了一下既忆,有以下幾點。

2. 常見需求

01. 父子組件通信

a. 父 -> 子(父組件傳遞數(shù)據(jù)給子組件)

使用 props嗦玖,具體查看文檔 - 使用 Prop 傳遞數(shù)據(jù)(https://cn.vuejs.org/v2/guide/components.html#使用-Prop-傳遞數(shù)據(jù))

b. 父 -> 子(在父組件上調(diào)用子組件內(nèi)的方法)

使用 ref患雇,具體查看文檔 - 子組件索引(https://cn.vuejs.org/v2/guide/components.html#子組件索引)

<!--父組件 template-->
<div id="parent">
  <!--子組件-->
  <user-profile ref="profile"></user-profile>
</div>
// 父組件 script
this.$refs.profile.someMethod();

注意:如果在子組件上設置 ref 屬性,則可以通過 this.$refs 獲取到該子組件對象宇挫,如果在普通的 html 標簽上設置 ref 屬性苛吱,則獲取到的是 Dom 節(jié)點。

c. 子 -> 父(在父組件上獲取子組件內(nèi)的數(shù)據(jù))

同上器瘪,也是利用 ref

// 父組件 script
let childData = this.$refs.profile.someData;

d. 子 -> 父(子組件內(nèi)觸發(fā)事件翠储,父組件監(jiān)聽事件)

父組件可以在使用子組件的地方直接用 v-on 來監(jiān)聽子組件觸發(fā)的事件,具體查看文檔 - 使用 v-on 綁定自定義事件(https://cn.vuejs.org/v2/guide/components.html#使用-v-on-綁定自定義事件)

<!--父組件 template-->
<div id="parent">
  <!--子組件-->
  <user-profile @childTrigger="parentHandle"></user-profile>
</div>
// 父組件 script
methods: {
    parentHandle(params){
        // 這個方法在子組件 emit childTrigger 事件后會執(zhí)行
        // params 為子組件里觸發(fā)事件時傳的參數(shù)
    }
}
// 子組件 user-profile script
this.$emit('childTrigger', params);

e. 子 -> 父(子組件傳值橡疼,父組件里使用援所,具體實現(xiàn)見 03

01總結:
應用場景示例:在父組件上打開側邊欄子組件,可以傳 prop visible(true)來控制側邊欄打開欣除;側邊欄內(nèi)部有關閉按鈕住拭,就在點擊關閉按鈕后觸發(fā)一個事件,父組件監(jiān)聽事件執(zhí)行方法將 data visible 改為 false
PS:父組件傳值到子組件滔岳,傳的值是 Object 類型瘟檩,子組件使用 v-model 可以修改該值(將某個表單元素的 v-model 設為該值),父組件可直接獲取到改變后的值澈蟆。

02. 全局函數(shù)

有時候會用到一些工具類函數(shù)墨辛,希望可以全局調(diào)用,而不是局限于某個組件中趴俘。

Step 1:
項目根目錄/static/js/ 目錄下新建一個 util.js 文件睹簇,將常用的工具函數(shù)寫在這里面。

Step 2:
index.html 里面引入 util.js寥闪,就可以在 .vue 文件里使用那些方法了太惠,如下:

<body>
  <div id="app"></div>
  <!-- 引入常用 js 方法 -->
  <script type="text/javascript" src="/static/js/util.js"></script>
   <!-- built files will be auto injected -->
</body>

02總結:
使用這個方法可以使得一些使用頻率高的函數(shù)可以在所有 .vue 文件中被調(diào)用,笨拙而又簡單疲憋。

03. slot

以前看文檔時一直不理解如何使用 slot凿渊,現(xiàn)在用多了 elementui 的組件之后,就漸漸發(fā)現(xiàn)了它的實用性缚柳。
簡單來說埃脏,使用 slot 可以使我們做到:在父組件里使用子組件時,在子組件里插入一些自定義的內(nèi)容(html 代碼啥的)秋忙,具體查看文檔:http://cn.vuejs.org/v2/guide/components.html#使用-Slot-分發(fā)內(nèi)容彩掐;
更神奇的功能是 作用域插槽,可以讓我們在父組件里使用子組件時灰追,獲取子組件傳來的數(shù)據(jù)堵幽,具體查看文檔:http://cn.vuejs.org/v2/guide/components.html#作用域插槽。

簡單應用示例

<!-- a-button 子組件 -->
<button type="button" class="a-button" @click="$emit('btn-click')"><slot></slot></button>
<!-- 這里監(jiān)聽了 button 的 click 事件弹澎,然后又觸發(fā)了 btn-click 事件 -->
<!-- 父組件 -->
<a-button @btn-click="handleClick">這里寫的東西會覆蓋子組件里的 slot 標簽所在的位置</a-button>
<!-- 這里監(jiān)聽了子元素觸發(fā)的 btn-click 事件朴下,然后執(zhí)行 handleClick 函數(shù) -->

渲染結果:

<button type="button" class="a-button">這里寫的東西會覆蓋子組件里的 slot 標簽所在的位置</button>

可以應用簡單的 slot 來達到為不同的按鈕填充文字的目的:

<a-button @click="handleClick">詳情</a-button>
<a-button @click="handleClick">搜索</a-button>

<!-- 渲染結果 -->
<button type="button" class="a-button">詳情</button>
<button type="button" class="a-button">搜索</button>

作用域插槽示例

<!-- 子組件 -->
<div class="child">
  <!-- slot 這個位置會在子組件被使用時被父組件傳來的 html 代碼覆蓋 -->
  <!-- slot 上的 text/child 就相當于傳給父組件的 props (假設 name 為子組件的 data,name: someChild) -->
  <slot text="hello from child" :child="name"></slot>
</div>

在父級中苦蒿,具有特殊屬性 scope<template> 元素殴胧,表示它是作用域插槽的模板。scope 的值對應一個臨時變量名刽肠,此變量接收從子組件中傳遞的 prop 對象:

<!-- 父組件 -->
<div class="parent">
  <child>
    <template scope="props">
      <span>hello from parent</span>
      <span>{{ props.text }}</span>
      <span>{{ props.child }}</span>
    </template>
  </child>
</div>

渲染結果:

<div class="parent">
  <div class="child">
    <span>hello from parent</span>
    <span>hello from child</span>
    <span>someChild</span>
  </div>
</div>

03總結:
應用場景示例:elementui 的 button 組件中有簡單插槽的使用溃肪,table 組件則使用到了 作用域插槽

<!-- button 組件 -->
<el-button>默認按鈕</el-button>
<el-button type="primary">主要按鈕</el-button>
<el-button type="text">文字按鈕</el-button>

<!-- table 組件 -->
<el-table
  :data="tableData">
  <el-table-column
    prop="zip"
    label="郵編"
    width="120">
  </el-table-column>
  <el-table-column
    fixed="right"
    label="操作"
    width="100">
    <template scope="scope">
      <el-button
        <!-- 可以通過 scope.$index 獲取到當前行的索引 -->
        @click.native.prevent="deleteRow(scope.$index)">
        移除
      </el-button>
    </template>
  </el-table-column>
</el-table>  

04. router 使用小記

vue-router 的使用音五,簡單來說就是通過配置,實現(xiàn)在不同的 url 路徑下羔沙,頁面渲染不同的組件躺涝。具體查看文檔:vue-router 2

使用示例
一級路由:

<!-- App.vue -->
<!-- 該組件為最高級父組件,使用 router-view 來根據(jù)路徑確定要顯示的子組件 -->
<template>
  <div id="app">
    <!-- router-view 位置用來顯示組件坚嗜,如顯示下面的 index.vue -->
    <router-view></router-view>
  </div>
</template>

二級路由(路由可嵌套):

<!-- page/index.vue -->
<!-- 該組件包含一個頂部欄和側邊菜單欄夯膀,內(nèi)容區(qū)使用 router-view 來根據(jù) url 路徑顯示子組件 -->
<template>
  <div class="index">
    <!-- 頂部導航條 -->
    <header class="main-header">
      ...
    </header>
    <!-- /頂部導航條 -->
    <!-- 側邊導航欄 -->
    <aside class="main-sidebar sidebar-gradient">
      ...
    </aside>
    <!-- /側邊導航欄 -->
    <!-- 根據(jù)頁面一級菜單的點擊而進行切換的內(nèi)容區(qū) -->
    <transition name="fade">
      <!-- router-view 位置用來顯示組件 --> 
      <router-view></router-view>
    </transition>
    <!-- /內(nèi)容區(qū) -->
  </div>
</template>

router 配置:

// router/index.js

import Vue from 'vue';
import Router from 'vue-router';
// 引入組件
import index from 'page/index'; // 該組件包含一個頂部欄和側邊菜單欄,內(nèi)容區(qū)使用 router-view 來根據(jù) url 路徑顯示子組件
import notFoundComponent from 'page/404'; // 該組件為 404 頁面苍蔬,當你路由使用 history 模式時需要用到
import monitorIndex from 'page/monitor/index'; // 該組件為一個監(jiān)控頁面诱建,用于顯示在 page/index.vue 頁面上的 router-view 處(即頁面的內(nèi)容區(qū)域)

Vue.use(Router);

// 定義 scrollBehavior 方法
const scrollBehavior = (to, from, savedPosition) => {
  if (savedPosition) {
    return savedPosition
  } else {
    return { x: 0, y: 0 }
  }
}

export default new Router({
  mode: 'history',
  // mode 默認 hash 值,但是 hash (url中包含 # 符號)不太好看也不符合我們一般的網(wǎng)址瀏覽習慣
  // 當你使用 history 模式時碟绑,URL 就像正常的 URL俺猿,例如 http://yoursite.com/user/id,也好看格仲!
 
  linkActiveClass: 'active',
  // 默認值: 'router-link-active'押袍,就是當前組件被激活,相應路由會自動添加類 'router-link-active'凯肋,這里是為了全局設置激活類名谊惭,如果不設置,直接用默認的也是可以的
  // 如:使用 router-link 組件來導航侮东,通過傳入 `to` 屬性指定鏈接
  // <router-link to="/foo">Go to Foo</router-link>
  // <router-link> 默認會被渲染成一個 `<a>` 標簽圈盔,'/foo' 路由下的組件顯示時,該 a 標簽上會自動添加類 'active'
    
  scrollBehavior: scrollBehavior,
  // 通過這個屬性(是個函數(shù))悄雅,可以讓應用像瀏覽器的原生表現(xiàn)那樣药磺,在按下 后退/前進 按鈕時,簡單地讓頁面滾動到頂部或原來的位置煤伟,如果不設置癌佩,則組件切換時滾動條位置不變
  
  routes: [
    {
      // 一級路由
      path: '/',
      component: index,
      children: [
        // 二級路由
        // -----------默認首頁-------------
        // 當 / 匹配成功,monitorIndex 會被渲染在 index 的 <router-view> 中
        { path: '', component: monitorIndex, alias: 'index.html' },
        // 這里的 alias 'index.html' 為當前頁面的別名
        // http://localhost:8080/index.html 等同于 http://localhost:8080/ 
        
        // -----------監(jiān)控中心-------------
        {
          // 當 /monitor 匹配成功便锨,
          // monitorIndex 會被渲染在 index 的 <router-view> 中
          path: 'monitor',
          name: '監(jiān)控中心',
          component: monitorIndex
        }
      ]
    },
    
    // 同一個路徑可以匹配多個路由围辙,此時,匹配的優(yōu)先級就按照路由的定義順序:誰先定義的放案,誰的優(yōu)先級就最高
    // 因此下面的路由配置為備用姚建,如果某個路徑未被配置顯示相應的組件,則顯示 404 頁面
    { path: '*', component: notFoundComponent }
  ]
});

引入 router 配置:

// main.js 

import Vue from 'vue';

// 引入 element ui 組件
import { Dropdown, DropdownMenu ...} from 'element-ui';

// 引入 App.vue
import App from './App';

// 引入 router 配置
import router from './router'; // 默認會找到 router 文件夾下的 index.js 文件

// 引入項目圖標的 sprite css吱殉,可以簡單的通過這種方式引入 css 文件
import './assets/css/sprite.css'

// 使用 element ui 組件
Vue.use(Dropdown)
Vue.use(DropdownMenu)
...

new Vue({
  el: '#app',
  router, // 使用 router 配置
  template: '<App/>',
  components: { App },
});

04總結:
關于 vue-router 的使用掸冤,看文檔一般都能解決你的疑問,vue-router 2友雳。
其他參考文章:Vue.js系列之vue-router(中)(4)
PS:使用 history 模式的話稿湿,還需要 后臺配置 支持。因為我們的應用是個單頁客戶端應用押赊,如果后臺沒有正確的配置饺藤,當用戶在瀏覽器直接訪問 http://oursite.com/user/id 就會返回 404(因為的確找不到該頁面),這就不好看了。并且在后臺配置后涕俗,還需要前端來提供 404 頁面罗丰,我上面的示例代碼中有提到,可供參考再姑。

05. 測試接口

使用 Vue 開發(fā)單頁應用時萌抵,前后端分離開發(fā),進度不一元镀。因此前端有時候就需要自己模擬接口的 json 文件绍填,然后直接使用異步請求方法(如 ajax) 去獲取數(shù)據(jù),渲染頁面凹联,測試代碼等沐兰。

Step 1:
項目根目錄/static/api/ 目錄下新建一個 test.json 文件,寫入模擬的接口數(shù)據(jù):

{
  "status": true,
  "data": {
    ...
  }
}

Step 2:
.vue 組件文件里任意需要請求數(shù)據(jù)的方法里(如 created 鉤子蔽挠,或者某個 methods 方法里)編寫相關代碼:

let vm = this;
// ajax 請求數(shù)據(jù)
$.ajax({
    type: 'GET',
    url: 'static/api/test.json',
    data: '',
    beforeSend: function() {
      // 顯示 Loading
      vm.loading = true;
    },
    complete: function() {
      // 隱藏 Loading
      vm.loading = false;
    },
    success: function(data) {
      // 處理返回數(shù)據(jù)
      ...
    },
    error: function() {
      // 數(shù)據(jù)請求失敗住闯,給用戶適當?shù)姆答佇畔?      ...
    },
    dataType: 'json'
});

05總結:
在后端尚未提供接口時,我都是用這個方法來測試前端獲取數(shù)據(jù)和處理數(shù)據(jù)的代碼是否正確澳淑。

3. 零碎問題

01. prop 傳值小技巧

我們可以為組件的 props 指定驗證規(guī)格比原。如果傳入的數(shù)據(jù)不符合規(guī)格,Vue 會發(fā)出警告杠巡。當組件給其他人使用時量窘,這很有用。

示例如下:

  props: {
    // 基礎類型檢測 (`null` 意思是任何類型都可以)
    propA: Number,
    // 多種類型
    propB: [String, Number],
    // 必傳且是字符串
    propC: {
      type: String,
      required: true
    },
    // 數(shù)字氢拥,有默認值
    propD: {
      type: Number,
      default: 100
    },
    // 數(shù)組/對象的默認值應當由一個工廠函數(shù)返回
    propE: {
      type: Object,
      default: function () {
        return { message: 'hello' }
      }
    },
    // 自定義驗證函數(shù)
    propF: {
      validator: function (value) {
        return value > 10
      }
    }
  }

愚蠢的我每次想要傳 Number 或者 Boolean 類型的值到子組件時蚌铜,都在父組件里定義好值,然后再綁定到子組件上:

// 這樣會報錯嫩海,因為 show type 為 Boolean冬殃,rows type 為 Number
// 默認情況下直接傳值,子組件接收到的都是 String 類型

// template
<child show="true" rows="6"></child>
// 于是我這樣做:

// template
<child :show="show" :rows="rows"></child>

// script
show: true,
rows: 6
// 實際上可以直接這樣做:

// template
<child :show="true" :rows="6"></child>

// 官網(wǎng)如是說:如果想傳遞一個實際的 number叁怪,需要使用 v-bind 审葬,從而讓它的值被當作 JavaScript 表達式計算。

小技巧:當某個 prop 類型為 Boolean 時奕谭,可以直接把該 prop 的名稱寫在組件上涣觉,默認會傳 true,不寫的話默認為 false血柳。比如 <child show :rows="6"></child> 這么寫官册,子組件內(nèi)部就能收到 show 為 true。

02. autoprefixer

有些人會問如何在項目里使用 autoprefixer 插件混驰,事實上使用 vue-cliwebpack 模板生成的項目里已經(jīng)帶有 autoprefixer 的使用了攀隔,如下圖:

autoprefixer

03. build 時不生成 .map 文件

對項目進行 npm run build 操作后皂贩,發(fā)現(xiàn)生成的文件超大(比想象中的大)栖榨,尤其是那些 .map 文件昆汹,不過,我們可以通過配置選擇不生成該類文件婴栽。

// 項目根目錄/config/index.js

var path = require('path')

module.exports = {
  build: {
    ...
    productionSourceMap: false, // 將該值設為 false满粗,就不會生成 .map 文件了
    
    // Gzip off by default as many popular static hosts such as
    // Surge or Netlify already gzip all static assets for you.
    // Before setting to `true`, make sure to:
    // npm install --save-dev compression-webpack-plugin
    productionGzip: false,
    productionGzipExtensions: ['js', 'css'],
    ...
  },
  dev: {
    ...
  }
}

4. 總結

一句話,有空多看文檔愚争,可以避免很多實踐中的問題映皆。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市轰枝,隨后出現(xiàn)的幾起案子捅彻,更是在濱河造成了極大的恐慌,老刑警劉巖鞍陨,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件步淹,死亡現(xiàn)場離奇詭異,居然都是意外死亡诚撵,警方通過查閱死者的電腦和手機缭裆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來寿烟,“玉大人澈驼,你說我怎么就攤上這事∩肝洌” “怎么了缝其?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長徘六。 經(jīng)常有香客問我内边,道長,這世上最難降的妖魔是什么硕噩? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任假残,我火速辦了婚禮,結果婚禮上炉擅,老公的妹妹穿的比我還像新娘辉懒。我一直安慰自己,他們只是感情好谍失,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布眶俩。 她就那樣靜靜地躺著,像睡著了一般快鱼。 火紅的嫁衣襯著肌膚如雪颠印。 梳的紋絲不亂的頭發(fā)上纲岭,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天,我揣著相機與錄音线罕,去河邊找鬼止潮。 笑死,一個胖子當著我的面吹牛钞楼,可吹牛的內(nèi)容都是我干的喇闸。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼询件,長吁一口氣:“原來是場噩夢啊……” “哼燃乍!你這毒婦竟也來了?” 一聲冷哼從身側響起宛琅,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤刻蟹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后嘿辟,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體舆瘪,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年仓洼,在試婚紗的時候發(fā)現(xiàn)自己被綠了介陶。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡色建,死狀恐怖哺呜,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情箕戳,我是刑警寧澤某残,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站陵吸,受9級特大地震影響玻墅,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜壮虫,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一澳厢、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧囚似,春花似錦剩拢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至募狂,卻和暖如春办素,著一層夾襖步出監(jiān)牢的瞬間角雷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工性穿, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留勺三,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓季二,卻偏偏與公主長得像檩咱,于是被迫代替她去往敵國和親揭措。 傳聞我的和親對象是個殘疾皇子胯舷,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 這篇筆記主要包含 Vue 2 不同于 Vue 1 或者特有的內(nèi)容,還有我對于 Vue 1.0 印象不深的內(nèi)容绊含。關于...
    云之外閱讀 5,050評論 0 29
  • 1.安裝 可以簡單地在頁面引入Vue.js作為獨立版本桑嘶,Vue即被注冊為全局變量,可以在頁面使用了躬充。 如果希望搭建...
    Awey閱讀 11,027評論 4 129
  • R:《非暴力溝通》,馬歇爾·盧森堡 (Marshall B.Rosenberg)(作者),阮胤華(譯者),華夏出版...
    悅恩haiyan閱讀 118評論 0 0
  • 來自北方逃顶,喜歡喝酒,97年生人充甚。短短幾句概括下來的就是我以政。 特想和別人分享我的故事,卻又不知從何說起伴找。眼下的生活挺...
    枯骨成雙i閱讀 401評論 0 1