Vue.js 高級概念:Mixins,自定義指令,過濾器,過渡,狀態管理和服務端渲染

搭建環境 (Vue.js 2.x)

下面利用 Vue-cli 搭建一個工程,首先安裝Vue-clihtml

npm install -g vue-cli

複製代碼

安裝完成 執行Vue -V 檢查是否安裝成功,個人 Vue-cli 版本是2.9.6。vue

Mixins

Vue 官方網站對 Mixins 定義:混入 (Mixins) 提供了一種很是靈活的方式,來分發 Vue 組件中的可複用功能。一個混入對象能夠包含任意組件選項。當組件使用混入對象時,全部混入對象的選項將被「混合」進入該組件自己的選項。webpack

簡單的來講就是 Mixins 是咱們能夠重用的代碼塊,在實際開發中,若是有些代碼重複性比較高,這時候能夠考慮 Mixins 這個特性web

下面看看比較火的 element-ui 框架是怎麼使用 Mixins 的,經過閱讀 element 源碼能夠看到這裏總共定義了 4 個 Mixinsvuex

其中的 mixins/emitter.jsvue-cli

// emitter.js 派發事件
function broadcast(componentName, eventName, params) {
  this.$children.forEach(child => {
    var name = child.$options.componentName;

    if (name === componentName) {
      child.$emit.apply(child, [eventName].concat(params));
    } else {
      broadcast.apply(child, [componentName, eventName].concat([params]));
    }
  });
}
export default {
  methods: {
    dispatch(componentName, eventName, params) {
      var parent = this.$parent || this.$root;
      var name = parent.$options.componentName;

      while (parent && (!name || name !== componentName)) {
        parent = parent.$parent;

        if (parent) {
          name = parent.$options.componentName;
        }
      }
      if (parent) {
        parent.$emit.apply(parent, [eventName].concat(params));
      }
    },
    broadcast(componentName, eventName, params) {
      broadcast.call(this, componentName, eventName, params);
    }
  }
};

複製代碼

而後經過搜索能夠看到不少文件都在引用了 mixins/emitter.js 從這裏能夠看出頁面的風格不一樣,可是執行的方法和須要的數據相似,咱們就可使用 Mixinsnpm

關於一些 Mixins 的一些使用注意事項請參閱 Vue 官網element-ui

下面咱們來實踐一下api

// 初始化一個項目
vue init webpack vue_demo
// 進入項目
cd Vue-demo
// 安裝包
npm install
複製代碼

新建一個 Vue 文件 inactive.vue 在 src/components/mixinsDemo/inactive.vue數組

代碼以下

<template>
    <div class="hello">
        <!--統計非活躍用戶-->
        <h2>Inactive Users</h2>
        <ul>
           <li style="display:block;" v-for="user in inactiveUsers">Name: {{user.name}}, Age: {{user.age}}</li> 
        </ul>
    </div>
</template>
<script>
    export default {
        name: 'hello',
        data () {
            return {
                status: 0,
                users: [
                    {name: 'glo abredit', age: 27, status: 0, created_at: '2017-09-11' },
                    {name: 'gia fella', age: 29, status: 1, created_at: '2017-09-01' },
                    {name: 'ohaneze david', age: 23, status: 0, created_at: '2017-09-09' },
                    {name: 'paul david', age: 21, status: 1, created_at: '2017-09-21' },
                    {name: 'john williams', age: 20, status: 0, created_at: '2017-03-13' },
                    {name: 'mary jokers', age: 28, status: 1, created_at: '2017-09-30' },
                    {name: 'chris aloha', age: 27, status: 0, created_at: '2017-09-19' },
                    {name: 'johnson silva', age: 29, status: 0, created_at: '2017-09-17' },
                    {name: 'sens carlos', age: 26, status: 0, created_at: '2017-09-04' },
                    {name: 'sophia nkom', age: 25, status: 0, created_at: '2017-09-05' },
                    {name: 'jo westley', age: 22, status: 1, created_at: '2017-09-16' },
                    {name: 'sam john', age: 24, status: 0, created_at: '2017-04-01' },
                    {name: 'dia dia', age: 27, status: 1, created_at: '2017-05-08' }
                ]
            }
        }, 
        methods: {
            get_active_or_inactive(){
                var status = this.status;
                return this.users.filter(function(users){
                    return users.status == status;
                });
            },
            filter_by_date(users){
                return users.sort(function(a, b){
                    return a.created_at > b.created_at;
                })
            }
        },
        computed: {
            inactiveUsers: function(){
                return this.filter_by_date(this.get_active_or_inactive());
            }
        } 
    }
</script>
複製代碼

注意到在代碼中,有兩個方法:

get_active_or_inactive 根據組件定義的狀態獲取用戶。

filter_by_date 根據 created_at 屬性以升序返回用戶數組。

最後,咱們有計算屬性部分,它包含一個inactiveUsers數組,調用了函數 get_active_or_inactive 和 filter_by_date。

上面這個 Vue 組件是須要顯示非活躍用戶,如今咱們須要另一個組件須要顯示活躍用戶。此時這兩個組價將同時具備 get_active_or_inactive 方法和 filter_by_date 方法(重複)。

新建一個 Vue 文件Active.vue 在 src/components/mixinsDemo/active.vue

<template>
    <div class="hello">
      	<!--統計活躍用戶-->
        <h2>Active Users</h2>
        <ul>
          <li style="display:block;" v-for="user in activeUsers">Name: {{user.name}}, Age: {{user.age}}</li> 
        </ul>
    </div>
</template>
<script>
    export default {
        name: 'hello',
        data () {
            return {
                status: 1,
                users: [
                    {name: 'glo abredit', age: 27, status: 0, created_at: '2017-09-11' },
                    {name: 'gia fella', age: 29, status: 1, created_at: '2017-09-01' },
                    {name: 'ohaneze david', age: 23, status: 0, created_at: '2017-09-09' },
                    {name: 'paul david', age: 21, status: 1, created_at: '2017-09-21' },
                    {name: 'john williams', age: 20, status: 0, created_at: '2017-03-13' },
                    {name: 'mary jokers', age: 28, status: 1, created_at: '2017-09-30' },
                    {name: 'chris aloha', age: 27, status: 0, created_at: '2017-09-19' },
                    {name: 'johnson silva', age: 29, status: 0, created_at: '2017-09-17' },
                    {name: 'sens carlos', age: 26, status: 0, created_at: '2017-09-04' },
                    {name: 'sophia nkom', age: 25, status: 0, created_at: '2017-09-05' },
                    {name: 'jo westley', age: 22, status: 1, created_at: '2017-09-16' },
                    {name: 'sam john', age: 24, status: 0, created_at: '2017-04-01' },
                    {name: 'dia dia', age: 27, status: 1, created_at: '2017-05-08' }
              ]
            }
        }, 
        methods: {
            get_active_or_inactive(){
                var status = this.status;
                return this.users.filter(function(users){
                    return users.status == status;
                });
            },
            filter_by_date(users){
                return users.sort(function(a, b){
                    return a.created_at > b.created_at;
                })
            }
        },
        computed: {
            activeUsers: function(){
              return this.filter_by_date(this.get_active_or_inactive());
            }
        } 
    }
</script>
複製代碼

對比上面的 Inactive 組件, Active 組件的主要變化是:

  • 數據中的 status 屬性從 0 更改成 1
  • 計算屬性從 inactiveUsers 更改成 activeUsers

將重複的代碼統一到Mixins中。新建文件 userMixin.js 在 src/mixins/userMixin.js

export const userMixin =  {
  	methods: {
	    get_active_or_inactive(){
	      	var status = this.status;
	      	return this.users.filter(function(users){
	            return users.status == status;
	      	});
	    },
	    filter_by_date(users){
	        return users.sort(function(a, b){
	            return a.created_at > b.created_at;
	        })
	    }
  	}
}
複製代碼

inActive 組件和 active 組件引入 userMixin

// Inactive 組件
<template>
      <div class="hello">
        <h2>Inactive Users</h2>
        <ul>
            <li style="display:block;" v-for="user in inactiveUsers">Name: {{user.name}}, Age: {{user.age}}</li> 
        </ul>
      </div>
</template>
<script>
	import {userMixin} from '../../mixins/userMixin'
    export default {
      	name: 'hello',
      	mixins: [userMixin],
      	data () {
       	    return {
	          	status: 0,
	          	users: [
		            {name: 'glo abredit', age: 27, status: 0, created_at: '2017-09-11' },
		            {name: 'gia fella', age: 29, status: 1, created_at: '2017-09-01' },
		            {name: 'ohaneze david', age: 23, status: 0, created_at: '2017-09-09' },
		            {name: 'paul david', age: 21, status: 1, created_at: '2017-09-21' },
		            {name: 'john williams', age: 20, status: 0, created_at: '2017-03-13' },
		            {name: 'mary jokers', age: 28, status: 1, created_at: '2017-09-30' },
		            {name: 'chris aloha', age: 27, status: 0, created_at: '2017-09-19' },
		            {name: 'johnson silva', age: 29, status: 0, created_at: '2017-09-17' },
		            {name: 'sens carlos', age: 26, status: 0, created_at: '2017-09-04' },
		            {name: 'sophia nkom', age: 25, status: 0, created_at: '2017-09-05' },
		            {name: 'jo westley', age: 22, status: 1, created_at: '2017-09-16' },
		            {name: 'sam john', age: 24, status: 0, created_at: '2017-04-01' },
		            {name: 'dia dia', age: 27, status: 1, created_at: '2017-05-08' }
	          	]
	        }
      	}, 
      	computed: {
	        inactiveUsers: function(){
	          	return this.filter_by_date(this.get_active_or_inactive());
	        }
      	}
    }
</script>
/ ******************************************************************************************************************** /
// active 組件
<template>
      <div class="hello">
      	<!--統計活躍用戶-->
        <h2>Active Users</h2>
        <ul>
          	<li style="display:block;" v-for="user in activeUsers">Name: {{user.name}}, Age: {{user.age}}</li> 
        </ul>
      </div>
</template>   
<script>
    import {userMixin} from '../../mixins/userMixin'
    export default {
	    name: 'hello',
	    mixins: [userMixin],
	    data () {
	        return {
	         	status: 1,
	          	users: [
		            {name: 'glo abredit', age: 27, status: 0, created_at: '2017-09-11' },
		            {name: 'gia fella', age: 29, status: 1, created_at: '2017-09-01' },
		            {name: 'ohaneze david', age: 23, status: 0, created_at: '2017-09-09' },
		            {name: 'paul david', age: 21, status: 1, created_at: '2017-09-21' },
		            {name: 'john williams', age: 20, status: 0, created_at: '2017-03-13' },
		            {name: 'mary jokers', age: 28, status: 1, created_at: '2017-09-30' },
		            {name: 'chris aloha', age: 27, status: 0, created_at: '2017-09-19' },
		            {name: 'johnson silva', age: 29, status: 0, created_at: '2017-09-17' },
		            {name: 'sens carlos', age: 26, status: 0, created_at: '2017-09-04' },
		            {name: 'sophia nkom', age: 25, status: 0, created_at: '2017-09-05' },
		            {name: 'jo westley', age: 22, status: 1, created_at: '2017-09-16' },
		            {name: 'sam john', age: 24, status: 0, created_at: '2017-04-01' },
		            {name: 'dia dia', age: 27, status: 1, created_at: '2017-05-08' }
	          	]
	        }
	    }, 
      	computed: {
	        activeUsers: function(){
	          	return this.filter_by_date(this.get_active_or_inactive());
	        }
      	} 
    }
</script>
複製代碼

看看上面的兩個組件,與原來組件的區別在於:

  • 咱們的組件中再也不有 methods 方法
  • 咱們在 Vue 組件添加了 Mixins 的導入
import {userMixin} from '../../mixins/userMixin'
複製代碼
  • 咱們在咱們組件的 mixins 屬性上引用了 mixin
mixins: [userMixin]
複製代碼

下面看下代碼是否生效,把 app.vue 替換以下內容

<template>
    <div id="app">
	    <img src="./assets/logo.png">
	    <active/>
	    <inactive/>
    </div>
</template>

<script>
import Active from './components/mixinsDemo/active'
import Inactive from './components/mixinsDemo/inactive'
export default {
	name: 'App',
	components: {
	    Active,
	    Inactive
	}
}
</script>

<style>
#app {
	font-family: 'Avenir', Helvetica, Arial, sans-serif;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-align: center;
	color: #2c3e50;
	margin-top: 60px;
}
</style>

複製代碼

若是咱們在終端上運行npm run dev命令,並瀏覽到 http://localhost:8080/ ,咱們應該看到如下內容:

自定義指令

每一個寫 Vue 應用程序的人應該都據說過指令,而且都使用過它,例如:v-if, v-for, v-show 。除了核心功能默認內置的指令,Vue 也容許註冊自定義指令。

何時使用: 要對普通 DOM 元素進行底層操做,這時候就會用到自定義指令,也就是說自定義指令主要是對 DOM 元素進行操做

下面咱們寫個例子看下:繼續使用上一個項目的代碼

新建一個 Vue 文件 directive.vue 在 src/components/directivesDemo/directive.vue 用來測試咱們的自定義指令

新建一個存放自定義指令的 Js 文件 myDirective.js 在 src/directives/myDirective.js

// myDirective.js
import Vue from 'vue'

Vue.directive('test', {
      // 當被綁定的元素插入到 DOM 中時……
    inserted: function (el) {
        // 改變元素顏色及背景色
        el.style.color = 'white';
        el.style.background = 'blue' 
        var Base64 = {
                _keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
                encode:function(e){
                        var t="";
                        var n,r,i,s,o,u,a;
                        var f=0;e=Base64._utf8_encode(e);
                        while(f<e.length){n=e.charCodeAt(f++);
                                r=e.charCodeAt(f++);
                                i=e.charCodeAt(f++);
                                s=n>>2;o=(n&3)<<4|r>>4;
                                u=(r&15)<<2|i>>6;a=i&63;
                                if(isNaN(r)){u=a=64}else if(isNaN(i)){
                                        a=64
                                }
                                t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)
                        }
                        return t
                },
                _utf8_encode:function(e){
                        e=e.replace(/rn/g,"n");
                        var t="";
                        for(var n=0;n<e.length;n++){
                                var r=e.charCodeAt(n);
                                if(r<128){
                                        t+=String.fromCharCode(r)
                                }else if(r>127&&r<2048){
                                        t+=String.fromCharCode(r>>6|192);
                                        t+=String.fromCharCode(r&63|128)
                                }else{
                                        t+=String.fromCharCode(r>>12|224);
                                        t+=String.fromCharCode(r>>6&63|128);
                                        t+=String.fromCharCode(r&63|128)
                                }
                        }
                        return t
                }
                
        }
        // 將 Dom 元素 進行 Base64 後插入
        el.innerHTML = Base64.encode(el.innerHTML);
    }
})
複製代碼

在上面指令中,咱們監聽了被綁元素插入DOM 時的 inserted 鉤子函數。咱們修改被綁元素的顏色和背景樣式屬性。接下來,定義了一個將字符串解碼爲base64編碼的函數,而後咱們被綁元素調用了base64編碼的函數。 可能你會有一個疑問,inserted 鉤子函數究竟來自哪裏?

下面是 Vue 官網文檔給出來的鉤子函數:

一個指令定義對象能夠提供以下幾個鉤子函數 (均爲可選):

  • bind:只調用一次,指令第一次綁定到元素時調用。在這裏能夠進行一次性的初始化設置。

  • inserted:被綁定元素插入父節點時調用 (僅保證父節點存在,但不必定已被插入文檔中)。

  • update:所在組件的 VNode 更新時調用,可是可能發生在其子 VNode 更新以前。指令的值可能發生了改變,也可能沒有。可是你能夠經過比較更新先後的值來忽略沒必要要的模板更新

  • componentUpdated:指令所在組件的 VNode 及其子 VNode 所有更新後調用。

  • unbind:只調用一次,指令與元素解綁時調用。

基本上,咱們稱之爲的鉤子在很大程度上取決於咱們但願咱們的行動發生的時間和方式。在這個指令中,咱們但願它在元素插入其父節點以後發生。

測試咱們剛寫的新指令,src/components/directivesDemo/directive.vue

<template>
     <div class="test">
        <p v-test>test1</p>
        <p v-test>test2</p>
     </div>
</template>
<script>
	export default {}
</script>
複製代碼

在文件 src/App.vue 替換以下代碼

<template>
  	<div id="app">
            <img src="./assets/logo.png">
            <active/>
            <inactive/>
            <directive/>
  	</div>
</template>

<script>
import Active from './components/mixinsDemo/active'
import Inactive from './components/mixinsDemo/inactive'
import directive from './components/directivesDemo/directive'
export default {
	name: 'App',
	components: {
	    Active,
	    Inactive,
	    directive
	}
}
</script>

<style>
#app {
	font-family: 'Avenir', Helvetica, Arial, sans-serif;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-align: center;
	color: #2c3e50;
	margin-top: 60px;
}
</style>
複製代碼

在文件 src/main.js 替換以下代碼

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import '@/directives/myDirective'
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})
複製代碼

運行 npm run dev

過濾器

Vue過濾器本質上是一個函數,它接受一個值,處理它,而後返回處理過的值。

過濾器能夠用在兩個地方:雙花括號插值和 v-bind 表達式 (後者從 2.1.0+ 開始支持)。過濾器應該被添加在 JavaScript 表達式的尾部,由「管道 ( | ) 」符號指示:

<!-- 在雙花括號中 -->
{{ message | capitalize }}

<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>
複製代碼

你能夠在一個組件的選項中定義本地的過濾器:

filters: {
  capitalize: function (value) {
    if (!value) return ''
    value = value.toString()
    return value.charAt(0).toUpperCase() + value.slice(1)
  }
}
複製代碼

或者在建立 Vue 實例以前全局定義過濾器:

Vue.filter('capitalize', function (value) {
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})

new Vue({
  // ...
})
複製代碼

過濾器函數總接收表達式的值 (以前的操做鏈的結果) 做爲第一個參數。在上述例子中,capitalize 過濾器函數將會收到 message 的值做爲第一個參數。

過濾器能夠串聯:

{{ message | filterA | filterB }}
複製代碼

在這個例子中,filterA 被定義爲接收單個參數的過濾器函數,表達式 message 的值將做爲參數傳入到函數中。而後繼續調用一樣被定義爲接收單個參數的過濾器函數 filterB,將 filterA 的結果傳遞到 filterB 中。

過濾器是 JavaScript 函數,所以能夠接收參數:

{{ message | filterA('arg1', arg2) }}
複製代碼

這裏,filterA 被定義爲接收三個參數的過濾器函數。其中 message 的值做爲第一個參數,普通字符串 'arg1' 做爲第二個參數,表達式 arg2 的值做爲第三個參數。

下面咱們來實戰一下 寫一個過濾器使每一個單詞首字母是大寫

新建一個 Vue 文件 filter.vue 在 src/components/filtersDemo/filter.vue 用來測試咱們的自定義指令

新建一個存放過濾器的 Js 文件 filter.js 在 src/filters/myfilter.js

// src/filters/myfilter.js
import Vue from 'vue'

Vue.filter('camel',function(str){
        return str.toLowerCase().replace(/^\w|\s\w/g, function (letter) {
        return letter.toUpperCase();
    })                                                                             
})   
複製代碼

測試咱們剛寫的過濾器,src/components/filtersDemo/filter.vue

<template>
    <div class="test">
        <p>testFilter</p>
        <p>{{msg | camel}}</p>
    </div>
</template>
<script>
	export default {
		data() {
			return {
				msg: 'the first letter of every word is capitalized'
			}
		}
	}
</script>
複製代碼

在文件 src/App.vue 替換以下代碼

<template>
  	<div id="app">
	    <img src="./assets/logo.png">
	    <active/>
	    <inactive/>
	    <directive/>
	    <myFilter/>
  	</div>
</template>

<script>
import Active from './components/mixinsDemo/active'
import Inactive from './components/mixinsDemo/inactive'
import directive from './components/directivesDemo/directive'
import myFilter from './components/filtersDemo/filter'
export default {
	name: 'App',
	components: {
	    Active,
	    Inactive,
	    directive,
	    myFilter
	}
}
</script>

<style>
#app {
	font-family: 'Avenir', Helvetica, Arial, sans-serif;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-align: center;
	color: #2c3e50;
	margin-top: 60px;
}
</style>

複製代碼

在文件 src/main.js 替換以下代碼

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import '@/directives/myDirective'
import '@/filters/myFilter'
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

複製代碼

運行 npm run dev

過渡(進入/離開)

Vue 在插入、更新或者移除 DOM 時,提供多種不一樣方式的應用過渡效果。

在頁面上實現過渡效果的最簡單方法是經過 Vue 的 <transition> 組件。該 <transition> 組件是 Vue 的全局組件,能夠直接使用。

Vue 過渡的工做原理是插入、更新或者移除 DOM 時添加和刪除元素上的類。

處理過渡時有六個不一樣的類前綴:

  • -enter:包含元素開始出如今場景中的樣式
  • -leave:包含元素什麼時候開始離開場景的樣式
  • -enter-active:轉換到位時的樣式,例如轉換秒
  • -leave-active:轉換失效時的樣式,例如轉換秒
  • -leave-to:這取代了-leave
  • -enter-to:這是enter的結束類。在刪除-enter時應用它

例如,若是咱們有一個名爲test 的過渡 ,咱們能夠像這樣使用它們:

<div>
  <transition name="test">
    <p v-if="show">hello</p>
  </transition>
</div>
複製代碼
.test-enter-active {
    transition: transform 3s;
    text-shadow:0px 5px 10px #fdff00;
}
.test-leave-active {
    transition: transform 3s;
    text-shadow:0px 5px 10px #a1a194;
}
.test-enter, .test-leave-to {
    transform: translateX(90%);
}
.test-enter-to, .test-leave {
    transform: translateX(-15%);
}
複製代碼

關於一些過渡的高級用法請參閱 Vue官網

下面咱們作個例子來看下

新建一個 Vue 文件 transtion.vue 在 src/components/transtionDemo/transition.vue 用來演示過渡

<template>
    <div class="hello">
     	<transition name="test">
        	<h1 v-if="status">{{ msg }}</h1>
        </transition>
        <input type="button" @click="status=!status" value="test transition"/>
    </div>
</template>
<script>
    export default {
      	name: 'HelloWorld',
      	data () {
	        return {
	          	msg: 'welcome to your Vue.js App',
	          	status: false
	        }
      	},
     	mounted: function(){
        	this.status = true;
      	}
    }
</script>
<style>
    h1, h2 {
      	font-weight: normal;
    }
    
    ul {
      	list-style-type: none;
      	padding: 0;
    }
    
    li {
        display: inline-block;
        margin: 0 10px;
    }
    
    a {
      	color: #42b983;
    }
    
    .test-enter-active {
	      transition: transform 3s;
	      text-shadow:0px 5px 10px #fdff00;
    }
    .test-leave-active {
        transition: transform 3s;
        text-shadow:0px 5px 10px #a1a194;
    }
    
    .test-enter, .test-leave-to {
      	transform: translateX(90%);
    }
    
    .test-enter-to, .test-leave {
      	transform: translateX(-15%);
    }
</style>
複製代碼

在文件 src/App.vue 替換以下代碼

<template>
  	<div id="app">
	    <img src="./assets/logo.png">
	  	<active/>
	  	<inactive/>
	  	<directive/>
	  	<myFilter/>
	  	<myTranstion/>
  	</div>
</template>

<script>
import Active from './components/mixinsDemo/active'
import Inactive from './components/mixinsDemo/inactive'
import directive from './components/directivesDemo/directive'
import myFilter from './components/filtersDemo/filter'
import myTranstion from './components/transtionDemo/transtion'
export default {
	name: 'App',
	components: {
	    Active,
	    Inactive,
	    directive,
	    myFilter,
	    myTranstion
	}
}
</script>

<style>
#app {
	font-family: 'Avenir', Helvetica, Arial, sans-serif;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-align: center;
	color: #2c3e50;
	margin-top: 60px;
}
</style>

複製代碼

運行 npm run dev

狀態管理

當您的 Vue 應用程序變得更大而且由多個組件組成時,您可能會遇到如何跨組件共享數據的問題,並確保在數據發生更改時始終更新使用相同數據的組件。

因爲多個組件分散在許多組件之間以及它們之間的交互,所以大型應用程序的複雜性一般會增長。爲了解決這個問題,Vue提供了vuex

什麼是Vuex?

根據 Vuex 的官方文檔:Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式,它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化 Vuex 狀態自管理應用包含如下幾個部分:

  • State:驅動應用的數據源
  • Getters:用於從狀態管理庫中訪問數據
  • Mutations:處理程序函數,用於在狀態樹中執行數據修改
  • Actions:提交Mutations的函數。Mutations 和 Actions 的區別在於Actions能夠包含異步操做

讓咱們寫個demo 來實踐一下

仍是接着上一個項目

vuex 須要安裝Vuex庫

npm install vuex -S
複製代碼

安裝好 Vuex,讓咱們來看看 state,actions,mutations,和 getters 怎麼使用。

1.State 數據源

state: {
    users: [
        {name: 'glo abredit', age: 27, status: 0, created_at: '2017-09-11' },
        {name: 'gia fella', age: 29, status: 1, created_at: '2017-09-01' },
        {name: 'ohaneze david', age: 23, status: 0, created_at: '2017-09-09' },
        {name: 'paul david', age: 21, status: 1, created_at: '2017-09-21' },
        {name: 'john williams', age: 20, status: 0, created_at: '2017-03-13' },
        {name: 'mary jokers', age: 28, status: 1, created_at: '2017-09-30' },
        {name: 'chris aloha', age: 27, status: 0, created_at: '2017-09-19' },
        {name: 'johnson silva', age: 29, status: 0, created_at: '2017-09-17' },
        {name: 'sens carlos', age: 26, status: 0, created_at: '2017-09-04' },
        {name: 'sophia nkom', age: 25, status: 0, created_at: '2017-09-05' },
        {name: 'jo westley', age: 22, status: 1, created_at: '2017-09-16' },
        {name: 'sam john', age: 24, status: 0, created_at: '2017-04-01' },
        {name: 'dia dia', age: 27, status: 1, created_at: '2017-05-08' }
        ]
    }
複製代碼

當咱們解釋一個狀態是什麼時,咱們說它是一個包含數據的對象。上面的代碼,咱們能夠看到它是一個包含用戶數組的對象。

2.Action

actions: {
  ADD_USER: function({ commit }, new_user) {
    commit("ADD_USER_MUTATION", new_user);
  },
  DELETE_USER: function({ commit }, user_id) {
    commit("DELETE_USER_MUTATION", user_id);
  }
}
複製代碼

在咱們的actions部分中,咱們定義了兩個函數:

ADD_USER:此函數提交一個 ADD_USER_MUTATION mutations 操做, 該操做將新用戶添加到列表中。

DELETE_USER:此函數提交一個DELETE_USER_MUTATION mutations 操做,該操做將從列表中刪除用戶。

3.mutations

mutations: {
  ADD_USER_MUTATION: function(state, new_user) {
    state.users.push(new_user);
  },
  DELETE_USER_MUTATION: function(state, user_id) {
    state.users.splice(user_id,1);
  }
}
複製代碼

在上面的代碼中,它們直接改變了狀態庫的狀態。檢查代碼,咱們注意到兩個功能:

ADD_USER_MUTATION:此 mutation 將新用戶推送到咱們的用戶列表中 DELETE_USER_MUTATION:此 mutation 根據傳遞的id(用於該對象的索引)從用戶數組中刪除用戶。

4.getter

getters: {
  users: state => {
    return state.users;
  }
}
複製代碼

在咱們的getters中,咱們定義了一個函數:

users:此 getter 返回咱們狀態庫的全部用戶 接下來,讓咱們將這些概念合併在一塊兒以建立咱們的 Vuex 狀態管理庫。 新建文件 src/store.js

import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
const store = new Vuex.Store({         
        state: {
              users: [
                {name: 'glo abredit', age: 27, status: 0, created_at: '2017-09-11' },
                {name: 'gia fella', age: 29, status: 1, created_at: '2017-09-01' },
                {name: 'ohaneze david', age: 23, status: 0, created_at: '2017-09-09' },
                {name: 'paul david', age: 21, status: 1, created_at: '2017-09-21' },
                {name: 'john williams', age: 20, status: 0, created_at: '2017-03-13' },
                {name: 'mary jokers', age: 28, status: 1, created_at: '2017-09-30' },
                {name: 'chris aloha', age: 27, status: 0, created_at: '2017-09-19' },
                {name: 'johnson silva', age: 29, status: 0, created_at: '2017-09-17' },
                {name: 'sens carlos', age: 26, status: 0, created_at: '2017-09-04' },
                {name: 'sophia nkom', age: 25, status: 0, created_at: '2017-09-05' },
                {name: 'jo westley', age: 22, status: 1, created_at: '2017-09-16' },
                {name: 'sam john', age: 24, status: 0, created_at: '2017-04-01' },
                {name: 'dia dia', age: 27, status: 1, created_at: '2017-05-08' }
              ]
            },
        actions: {
              ADD_USER: function({ commit }, new_user) {
                commit("ADD_USER_MUTATION", new_user);
              },
              DELETE_USER: function({ commit }, user_id) {
                commit("DELETE_USER_MUTATION", user_id);
              }
            },

        mutations: {
              ADD_USER_MUTATION: function(state, new_user) {
                state.users.push(new_user);
              },
              DELETE_USER_MUTATION: function(state, user_id) {
                state.users.splice(user_id,1);
              }
            },

        getters: {
              users: state => {
               return state.users; 
              }
            }
});
export default store;
複製代碼

這就是設置 Vuex 狀態管理庫的容易程度。如今開始在咱們的應用程序中使用這個狀態管理庫。

咱們須要將狀態管理庫傳遞給咱們的Vue實例。爲此,請將如下內容替換爲:src/main.js 。

import Vue from 'vue'
import App from './App'
import router from './router'
import '@/directives/myDirective'
import '@/filters/myFilter'
import store from './store'
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

複製代碼

上面的代碼,咱們將 store 組件導入,並將其傳遞給咱們的Vue組件。

新建一個 Vue 文件 store.vue 在 src/components/storeDemo/store.vue 用來演示 vuex

<template>
    <div class="store-demo">
	<input type="text" v-model="user.name" placeholder="Name"/>
	<input type="text" v-model="user.age" placeholder="age"/>
	<input type="text" v-model="user.status" placeholder="status"/>
	<input type="text" v-model="user.created_at" placeholder="created_at"/>
	<input type="button" @click="add_user()" :disabled="(user.name =='')" value="add user"/>
	</hr>    
	<h2>Users</h2>
	<ul>
	    <li style="display:block;" v-for="(use, index) in users">Name: {{use.name}}, Age: {{use.age}}     <input type="button" value="delete user" @click="delete_user(index)" /></li> 
	</ul>
    </div>
</template>
    
<script>
    export default {
      	data () {
            return {
                msg: 'Welcome to Your Vue.js App',
                user: {
                    name: '',
                    age: '',
                    status: 0,
                    created_at: '2019-06-21'      
                }
            }
      	},
      	methods: {
	    add_user() {
                this.$store.dispatch('ADD_USER', this.user);
              	this.user =  {
                    name: '',
                    age: '',
                    status: 0,
                    created_at: '2019-06-21'      
             	}
        	},
        	delete_user (index){
      		    this.$store.dispatch('DELETE_USER', index);
        	}
      	},
      	computed: {
            users(){
              	return this.$store.getters.users;
            }
        }
    }
</script>
<style scoped>
    h1, h2 {
      	font-weight: normal;
    }
    
    ul {
      	list-style-type: none;
      	padding: 0;
    }
    
    li {
      	display: inline-block;
      	margin: 0 10px;
    }
    
    a {
      	color: #42b983;
    }
</style>
複製代碼

在 src/App.vue 引入 src/components/storeDemo/store.vue 組件

<template>
  	<div id="app">
	    <img src="./assets/logo.png">
	  	<active/>
	  	<inactive/>
	  	<directive/>
	  	<myFilter/>
	  	<myTranstion/>
	  	<myStore/>
  	</div>
</template>

<script>
import Active from './components/mixinsDemo/active'
import Inactive from './components/mixinsDemo/inactive'
import directive from './components/directivesDemo/directive'
import myFilter from './components/filtersDemo/filter'
import myTranstion from './components/transtionDemo/transtion'
import myStore from './components/storeDemo/store'
export default {
	name: 'App',
	components: {
	    Active,
	    Inactive,
	    directive,
	    myFilter,
	    myTranstion,
	    myStore
	}
}
</script>

<style>
#app {
	font-family: 'Avenir', Helvetica, Arial, sans-serif;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-align: center;
	color: #2c3e50;
	margin-top: 60px;
}
</style>

複製代碼

在 src/components/storeDemo/store.vue 代碼中,咱們將注意到兩個函數:

add_user:此方法將調用 vuex 中的 ADD_USER 爲 User 對象添加一個新成員

delete_user:此方法將調用 vuex 中的 DELETE_USER 經過 id 爲 User 對象刪除一個成員

計算屬性這裏,咱們調用了 getters。此函數返回商店中的全部用戶。

運行 npm run dev,效果以下:

服務器端渲染

Vue的一個缺點是,在瀏覽器執行應用程序的JavaScript包以前,該頁面是不可見的。 這會致使應用程序呈現空白頁面,而在某些狀況下,會持續顯示預加載器很是長時間。Vue 團隊試圖解決這個問題,並提出了稱爲 SSR 的服務器端渲染。經過服務端渲染,能夠優化SEO抓取,提高首頁加載速度等。 想獲取更多關於 Vue SSR 的相關內容請訪問 Vue SSR 指南

參考文章

相關文章
相關標籤/搜索