1. 程式人生 > >Vue.js(四) 元件(component)

Vue.js(四) 元件(component)

一:Vue元件簡介

傳統前端中一個網頁應用是由很多.html檔案組成,每個html檔案又分為三部分,第一部分就是<html>用於展示檢視,第二部分是<script type="text/javascript">用於和使用者互動,第三部分是<style>用於控制檢視的樣式。開發中一般會將js指令碼和樣式檔案單獨抽出來作為一個單獨的檔案。如果想在一個html中嵌入另一個html可以通過<iframe src="foo.html" />來實現。

現代前端中一個網頁應用是由多個.vue檔案組成,每個vue檔案又分為三部分,第一部分就是<template>

用於展示檢視,第二部分是<script>用於和使用者互動,第三部分是<style>用於控制檢視的樣式。開發中通常都將<template>、<script>、<style>放在一個.vue檔案中而不會分別獨立成一個檔案。如果想在一個vue中嵌入另一個vue可以通過註冊元件以自定義標籤形式來實現。

元件簡單的說就是一個.vue檔案,每個.vue檔案就是一個元件,每個.vue檔案對應著一個Vue例項(Vue類),一個應用程式是由很多個vue檔案組成,在vue檔案中可以巢狀其它vue檔案,最終一個應用程式就像一棵倒立的樹(元件)。元件是Vue中的最基礎最核心的單位。

在這裡插入圖片描述

一個元件(component)大概就是下面這個樣子:HelloWorld.vue

<template>
  <div>
    <span>{{ msg }}</span>
  </div>
</template>

<script>
export default {
  name: 'HelloWorld',
  data () {
    return {
      msg : 'Hello Vue!'
    }
  }
}
</script>

<style scoped>
span { color: red } </style>

二:Vue三大部分

1. < template >

模板是用於編寫檢視(DOM)的地方,通常都會放在一個跟元素下面,通常根元素都是div。

<template>
	<div>
		<!-- view -->
	</div>
</template>

2. < script >

2.1 script指令碼中包含兩部分

  • import(匯入):在傳統前端開發中匯入js檔案使用 <script src="js/jquery.js"></script>來匯入,在ES6中使用import 變數名 from '檔案路徑'語法來匯入,作用是將某個檔案建立成物件,然後將該物件賦值給一個變數名,可以匯入 .js .vue .json檔案,其中檔案字尾名也可以省略

    import commonUtil from '@/utils/CommonUtil.js'
    import foo from '@/components/Foo.vue'
    

    兩者效果類似

    var commonUtil = new CommonUtil();
    var foo = new Foo();
    
  • export(匯出):export default 用於匯出一個Vue的例項選項{ }, 被匯出的物件可以通過import來匯入,從而引用被匯入的物件的屬性和函式。在匯入時可以通過@符號來表示src,匯入時當字尾是.js、.vue、.json時是可以省略的,這些配置都可以在build/webpack.base.conf.js下的module.exports.resolve配置。在vue中匯出的物件是一個Vue物件(包含name、data、methods等屬性),Vue中有多個屬性。

    build/webpack.base.conf.js

    module.exports = {
      resolve: {
        extensions: ['.js', '.vue', '.json'],
        alias: {
          'vue$': 'vue/dist/vue.esm.js',
          '@': resolve('src'),
        }
      }
    },
    
    // 匯出預設的Vue物件
    export default {
    	// 配置Vue中的屬性,如name、data、methods等
    	name: 'HelloWorld',
    	data() {
    		return { foo: 'foo', bar: 'bar' }
    	},
    	methods: {
    		foo() {
    		
    		},
    		bar() {
    		
    		}
    	}
    }
    

2.2 import 和 export 示例

我們定義一個非常簡單的元件YesOrNoSelect.vue,元件中模板只有一個下拉框,匯出的Vue例項選項也只有name和data,一個非常簡單的樣式。我們在另一個元件HelloWorld.vlue中匯入importYesOrNoSelect.vue, 然後就可以在HelloWorld.vlue中來訪問YesOrNoSelect.vue元件中匯出的物件。

YesOrNoSelect.vue

<template>
    <select>
        <option v-for="item in options" v-bind:key="item.id">{{item.text}}</option>
    </select>
</template>

<script>
export default {
    name: 'YesOrNoSelector',
    data () {
        return {
            options: [
                {id: '', text:'全部'},
                {id: 0, text:'否'},
                {id: 1, text:'是'}
                ]
        }
    }
}
</script>

<style scoped>
select {
    width: 100px;
    height: 30px
}
</style>

HelloWorld.vue

<template>
  <div>
    <span>{{ msg }}</span>
  </div>
</template>

<script>
// 匯入Vue
import YesOrNoSelect from '@/components/YesOrNoSelect'

export default {
  name: 'HelloWorld',
  data () {
    return {
      msg : 'Hello Vue!',
      // 引用匯入的Vue的例項選項
      nameOfImportComponent: YesOrNoSelect.name,
      dataOfImportComponent: YesOrNoSelect.data()
    }
  }
}
</script>

在這裡插入圖片描述

3. < style>

style裡和傳統的css差不多,不同的是支援了更多的語法,比如scss、less、stylus等。

三:Vue生命週期

每個.vue檔案都對應著一個Vue例項物件,每個Vue例項物件從建立到銷燬都會經歷以下幾個過程:
在這裡插入圖片描述

開發中經常使用created函式做一些初始化工作,比如頁面一載入時執行的動作。

<template>
  <div>
    <span>{{ msg }}</span>
  </div>
</template>

<script>

export default {
  name: 'HelloWorld',
  data () {
    return {
      msg : 'Hello Vue!'
    }
  },
  created() {
    console.log('init method created :'+ this.msg)
  }
}
</script>

在這裡插入圖片描述

四:Vue選項options

一個Vue例項包含如下幾個屬性和函式,這些屬性和函式統稱為選項options(就像配置引數一樣)。下面使用虛擬碼列舉了Vue的一些常用的屬性和函式。

/**
* Vue 資料結構虛擬碼
*/
interface Vue {
	/** 元件名稱 */
	String name;
	/** 模板檢視 */
	String template;
	/** 在這裡定義方法,可以定義多個 */
	Object methods;
	/** 區域性註冊元件 */
	Object components;
	/** 計算屬性 */
	Object computed;
	/** 過濾器 用於格式化文字(如 金額、日期、貨幣) */
	Object filters;
	Object watch;
	/** 屬性(properties) */
	Object props;
	
	/** 區域性註冊指令 */
	Object directives;
	Object[] mixins;
	
	/**
	* 根據選項返回一個Vue例項
	* 類似於建構函式
	*/
	Vue extend (options) {

	}
	
	/** 
	* 定義雙向繫結的變數 
	* 在Vue例項中可以直接通過this來訪問data函式返回值的物件的屬性值
	*/
	public Object data {
		return { }
	}
	
	/**
	* Vue例項建立完成時執行的函式
	* 常用與做一些初始化操作,比如頁面一載入就需要執行的動作。
	*/
	public void created {
	
	}
	
	public void activated {
	
	}
}

五:使用元件

5.1 Vue全域性函式

  • Vue.directive(‘指令名稱’, { }) 全域性註冊自定義指令
  • Vue.component(‘元件名稱’, 元件例項) 全域性註冊元件
  • Vue.use(元件例項) 使用外掛,它需要在你呼叫 new Vue() 啟動應用之前完成:
  • Vue.filter(‘名稱’, function(value) { }) 全域性過濾器,格式化文字
  • Vue.extend(options) 構造一個Vue例項
  • Vue.set(object, key, value) 向物件新增響應式屬性

5.2 自定義標籤

5.2.1 定義需要被引入的元件YesOrNoSelect.vue

<template>
    <select>
        <option v-for="item in options" v-bind:key="item.id">{{item.text}}</option>
    </select>
</template>

<script>
export default {
    name: 'YesOrNoSelector',
    data () {
        return {
            options: [
                {id: '', text:'全部'},
                {id: 0, text:'否'},
                {id: 1, text:'是'}
                ]
        }
    }
}
</script>

<style scoped>
select {
    width: 100px;
    height: 30px
}
</style>

5.2.2 註冊元件
在main.js中全域性註冊

import YesOrNoSelect from '@/components/YesOrNoSelect'
Vue.component('yes-or-no-select', YesOrNoSelect)

或者在HelloWorld.vue中區域性註冊

<script>
import YesOrNoSelect from '@/components/YesOrNoSelect'

export default {
  name: 'HelloWorld',
  components: {
    YesOrNoSelect
  }
}
</script>

5.2.3 使用自定義的元件 HelloWorld.vue

<template>
  <div>
    YesOrNo: <yes-or-no-select />
  </div>
</template>

<script>

import YesOrNoSelect from '@/components/YesOrNoSelect'

export default {
  name: 'HelloWorld',
  data () {
    return {
      
    }
  }
}
</script>

在這裡插入圖片描述

5.3 過濾器

過濾器其實就是對輸入的值進行處理,返回處理後的值。

過濾器既可以在文字插值表示式中使用,也可以在v-bind等指令中使用。

5.3.1 在main.js中註冊過濾器

// 首字母大寫
Vue.filter('capitalize', function (value) {
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})

5.3.2 在模板中使用管道命令符 | 來對前面的值進行格式化處理
注意:管道命令符可以同時使用多次

<template>
  <div>
    文字插值:{{msg | capitalize}} <br>
    指令:<input v-bind:value="msg | capitalize" />
  </div>
</template>

<script>
  export default {
    name: 'HelloWorld',
    data () {
      return {
        msg: 'shanghai'
      }
    }
  }
</script>

在這裡插入圖片描述

5.4 使用外掛

在main.js中匯入第三方元件並使用元件

import ElementUI from 'element-ui'
// 使用時需要在你呼叫 new Vue() 啟動應用之前完成
Vue.use(ElementUI)

new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

5.5 計算屬性

計算屬性(computed):插值表示式{{ }}只適合比較簡單的計算,如果計算邏輯比較複雜可以放到computed中作為一個函式,然後在插值表示式中直接將這個函式作為一個普通屬性來使用。屬性名稱為計算屬性對應的函式名稱。

注意計算屬性會快取,當相關依賴沒有發生變化時是直接返回快取中的值而不會重新計算。

<template>
  <div>
    計算屬性: {{upperCase}} <br>
    區域性過濾器: {{realName | upperCaseFilter}} <br>
    方法呼叫: {{upperCaseMethod(realName)}}
  </div>
</template>

<script>

export default {
  name: 'HelloWorld',
  data () {
    return {
      realName: 'zhang san'
    }
  },
  computed: {
    upperCase () {
      return this.realName.toLowerCase().split(/\s+/).map(function(item) {
        return item.slice(0, 1).toUpperCase() + item.slice(1);
      }).join(' ');
    }
  },
  filters: {
    upperCaseFilter (value) {
      return value.toLowerCase().split(/\s+/).map(function(item) {
        return item.slice(0, 1).toUpperCase() + item.slice(1);
      }).join(' ');
    }
  },
  methods: {
    upperCaseMethod(value) {
      return value.toLowerCase().split(/\s+/).map(function(item) {
        return item.slice(0, 1).toUpperCase() + item.slice(1);
      }).join(' ');
    }
  }
}
</script>

在這裡插入圖片描述

使用方式 是否會快取 使用場景
計算屬性(computed) 直接作為普通屬性來使用 {{ foo }} 會快取(當依賴的值沒有發生變化時) 使用比較多,計算比較複雜的
過濾器(filter) 通過管道命令符|來使用{{value | foo}} 不會快取,每次都會執行函式 過濾資料或者格式化文字(日期、金額等)
方法(method) 方法呼叫通過小括號() { {foo(value) }} 不會快取,每次都會執行函式 一般的函式

相同點:其實三者都能達到相同的目的,只不過在使用方式上語法上有一點區別,應用場景上有一點點小區別。

5.6 偵聽屬性(watch)

監聽某個值的改變, 監聽的值要和watch中的函式名保持一致。功能上和oninput事件差不多。

<template>
  <div>
    <input v-model="keyword"/>
  </div>
</template>

<script>
  export default {
    name: 'HelloWorld',
    data () {
      return {
        keyword: ''
      }
    },
    watch: {
        keyword() {
          console.log('keyword=' + this.keyword)
        }
      }
    }
</script>

在這裡插入圖片描述

5.7 Vue.extend({ })

<template>
  <div>
    Vue.extend(options)
  </div>
</template>

<script>
  import Vue from 'vue'

  let options = {
    data () {
      return {
        msg: 'Hello Vue!',
        foo: 'bar'
      }
    },
    created () {
      console.log(this.msg)
    }
  }

  // 構造Vue
  let Component = Vue.extend(options)
  // 建立元件物件,會呼叫選項中的created函式
  let component = new Component()

  export default {

  }
</script>

在這裡插入圖片描述

5.8 mixin(混入)

mixin(混入): 就是預先定義一個Vue選項(options),此時稱之為混入(mixin),在建立Vue例項時將混入物件傳給Vue選項,由於混入物件定義了一些Vue選項,而在建立Vue例項時也會定義一些選項,兩者混合在一起,當重複時會根據一定的優先順序是使用混入物件的屬性還是使用Vue例項的屬性。

  • 當混入的data中的屬性和Vue例項中的data屬性名字重複時使用Vue例項中的值,不重複時取並集
  • 當混入的methods中的方法重名時取Vue例項中的method的
  • 當鉤子函式重名時,會取並集,會先呼叫混入的鉤子函式,然後再呼叫元件的鉤子函式。有點像建構函式中先呼叫父類的建構函式再呼叫子類的的建構函式的意思。
<template>
  <div>
    mixin
  </div>
</template>

<script>
  import Vue from 'vue'

  let mixin = {
    data () {
      return {
        foo: 'foo mixin',
        msg: 'msg mixin'
      }
    },
    methods: {
      foobar () {
        console.log("foobar method mixin")
      }
    },
    created () {
      console.log('created function mixin')
    }
  }

  let vm = new Vue({
    mixins: [mixin],
    data () {
      return {
        bar: 'bar self',
        msg: 'msg self'
      }
    },
    methods: {
      foobar () {
        console.log("foobar method self")
      }
    },
    created () {
      console.log('created function self')
    }
  })

  console.log(vm.$data)
  vm.foobar()

  export default {}
</script>

在這裡插入圖片描述

六:props

props可以為自定義標籤(元件)來自定義屬性。使用元件時可以通過自定義屬性來向子元件傳遞引數。

props的作用就是父元件(使用子元件的元件)向子元件(被引用的元件)傳遞引數。

Props型別:

  • 字串陣列形式 props: [‘foo’, ‘bar’, ‘foobar’]
  • 資料型別形式 { foo: String, bar: Number, baz: Boolean, foobar: Array, xxx: Object }

傳值方式:

  • 靜態傳值: 自定義屬性名=“值” 或者 v-bind:自定義屬性名=“表示式值”, 當值是數值或者布林型別時需要使用v-bind方式,因為數值和布林也是js中的表示式
  • 動態傳值: v-bind:自定義屬性名=“屬性值”

無論靜態傳值還是動態傳值推薦使用v-bind指令

6.1 YesOrNoSelect.vue定義子元件

聲明瞭兩個自定義屬性props,自定義屬性可以在指令或者文字插值表示式中使用:

  • options陣列型別,select標籤要迴圈的值。
  • index數值型別,預設被選中的option對應的索引, 如果不傳遞該屬性則預設為0。
<template>
  <label>
    <select v-model="index === undefined ? 0 : index">
      <option v-for="item in options" v-bind:key="item.id" :value="item.id">{{item.text}}</option>
    </select>
  </label>
</template>

<script>
  export default {