【轉載】Vue 2.x 實戰以後臺管理系統開發(二)

2. 常見需求

01. 父子組件通訊

a. 父 -> 子(父組件傳遞數據給子組件)javascript

使用 props,具體查看文檔 - 使用 Prop 傳遞數據(cn.vuejs.org/v2/guide/co…css

b. 父 -> 子(在父組件上調用子組件內的方法)html

使用 ref,具體查看文檔 - 子組件索引(cn.vuejs.org/v2/guide/co…前端

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

注意:若是在子組件上設置 ref 屬性,則能夠經過 this.$refs 獲取到該子組件對象,若是在普通的 html 標籤上設置 ref 屬性,則獲取到的是 Dom 節點。vue

c. 子 -> 父(在父組件上獲取子組件內的數據)java

同上,也是利用 refwebpack

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

d. 子 -> 父(子組件內觸發事件,父組件監聽事件)web

父組件能夠在使用子組件的地方直接用 v-on 來監聽子組件觸發的事件,具體查看文檔 - 使用 v-on 綁定自定義事件(cn.vuejs.org/v2/guide/co…ajax

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

e. 子 -> 父(子組件傳值,父組件裏使用,具體實現見 03vue-router

01總結:
應用場景示例:在父組件上打開側邊欄子組件,能夠傳 prop visible(true)來控制側邊欄打開;側邊欄內部有關閉按鈕,就在點擊關閉按鈕後觸發一個事件,父組件監聽事件執行方法將 data visible 改成 false
PS:父組件傳值到子組件,傳的值是 Object 類型,子組件使用 v-model 能夠修改該值(將某個表單元素的 v-model 設爲該值),父組件可直接獲取到改變後的值。

02. 全局函數

有時候會用到一些工具類函數,但願能夠全局調用,而不是侷限於某個組件中。

Step 1:
項目根目錄/static/js/ 目錄下新建一個 util.js 文件,將經常使用的工具函數寫在這裏面。

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總結:
使用這個方法可使得一些使用頻率高的函數能夠在全部 .vue 文件中被調用,笨拙而又簡單。

03. slot

之前看文檔時一直不理解如何使用 slot,如今用多了 elementui 的組件以後,就漸漸發現了它的實用性。
簡單來講,使用 slot 可使咱們作到:在父組件裏使用子組件時,在子組件裏插入一些自定義的內容(html 代碼啥的),具體查看文檔:cn.vuejs.org/v2/guide/co…
更神奇的功能是 做用域插槽,可讓咱們在父組件裏使用子組件時,獲取子組件傳來的數據,具體查看文檔:cn.vuejs.org/v2/guide/co…

簡單應用示例

<!-- a-button 子組件 --> <button type="button" class="a-button" @click="$emit('btn-click')"><slot></slot></button> <!-- 這裏監聽了 button 的 click 事件,而後又觸發了 btn-click 事件 -->
<!-- 父組件 --> <a-button @btn-click="handleClick">這裏寫的東西會覆蓋子組件裏的 slot 標籤所在的位置</a-button> <!-- 這裏監聽了子元素觸發的 btn-click 事件,而後執行 handleClick 函數 -->

渲染結果:

<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 的使用,簡單來講就是經過配置,實如今不一樣的 url 路徑下,頁面渲染不一樣的組件。具體查看文檔:vue-router 2

使用示例
一級路由:

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

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

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

router 配置:

// router/index.js import Vue from 'vue'; import Router from 'vue-router'; // 引入組件 import index from 'page/index'; // 該組件包含一個頂部欄和側邊菜單欄,內容區使用 router-view 來根據 url 路徑顯示子組件 import notFoundComponent from 'page/404'; // 該組件爲 404 頁面,當你路由使用 history 模式時須要用到 import monitorIndex from 'page/monitor/index'; // 該組件爲一個監控頁面,用於顯示在 page/index.vue 頁面上的 router-view 處(即頁面的內容區域) 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中包含 # 符號)不太好看也不符合咱們通常的網址瀏覽習慣 // 當你使用 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, // 經過這個屬性(是個函數),可讓應用像瀏覽器的原生表現那樣,在按下 後退/前進 按鈕時,簡單地讓頁面滾動到頂部或原來的位置,若是不設置,則組件切換時滾動條位置不變 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/ // -----------監控中心------------- { // 當 /monitor 匹配成功, // monitorIndex 會被渲染在 index 的 <router-view> 中 path: 'monitor', name: '監控中心', component: monitorIndex } ] }, // 同一個路徑能夠匹配多個路由,此時,匹配的優先級就按照路由的定義順序:誰先定義的,誰的優先級就最高 // 所以下面的路由配置爲備用,若是某個路徑未被配置顯示相應的組件,則顯示 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 開發單頁應用時,先後端分離開發,進度不一。所以前端有時候就須要本身模擬接口的 json 文件,而後直接使用異步請求方法(如 ajax) 去獲取數據,渲染頁面,測試代碼等。

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

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

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

let vm = this; // ajax 請求數據 $.ajax({ type: 'GET', url: 'static/api/test.json', data: '', beforeSend: function() { // 顯示 Loading vm.loading = true; }, complete: function() { // 隱藏 Loading vm.loading = false; }, success: function(data) { // 處理返回數據 ... }, error: function() { // 數據請求失敗,給用戶適當的反饋信息 ... }, dataType: 'json' });

05總結:
在後端還沒有提供接口時,我都是用這個方法來測試前端獲取數據和處理數據的代碼是否正確。

3. 零碎問題

01. prop 傳值小技巧

咱們能夠爲組件的 props 指定驗證規格。若是傳入的數據不符合規格,Vue 會發出警告。當組件給其餘人使用時,這頗有用。

示例以下:

props: {
    // 基礎類型檢測 (`null` 意思是任何類型均可以) propA: Number, // 多種類型 propB: [String, Number], // 必傳且是字符串 propC: { type: String, required: true }, // 數字,有默認值 propD: { type: Number, default: 100 }, // 數組/對象的默認值應當由一個工廠函數返回 propE: { type: Object, default: function () { return { message: 'hello' } } }, // 自定義驗證函數 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> // 官網如是說:若是想傳遞一個實際的 number,須要使用 v-bind ,從而讓它的值被看成 JavaScript 表達式計算。

小技巧:當某個 prop 類型爲 Boolean 時,能夠直接把該 prop 的名稱寫在組件上,默認會傳 true,不寫的話默認爲 false。好比 <child show :rows="6"></child> 這麼寫,子組件內部就能收到 show 爲 true。

02. autoprefixer

有些人會問如何在項目裏使用 autoprefixer 插件,事實上使用 vue-cliwebpack 模板生成的項目裏已經帶有 autoprefixer 的使用了,以下圖:

 

autoprefixer

 

03. build 時不生成 .map 文件

對項目進行 npm run build 操做後,發現生成的文件超大(比想象中的大),尤爲是那些 .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: { ... } }

原文連接:https://juejin.im/post/58f37bfe5c497d006c90ca28

相關文章
相關標籤/搜索