1. 程式人生 > 程式設計 >vue 擴充套件現有元件的操作

vue 擴充套件現有元件的操作

1. 使用vue.mixin全域性混入

混入 (mixins) 是一種分發 Vue 元件中可複用功能的非常靈活的方式。混入物件可以包含任意元件選項。當元件使用混入物件時,所有混入物件的選項將被混入該元件本身的選項。mixins 選項接受一個混合物件的陣列。

混入的主要用途

1、在你已經寫好了構造器後,需要增加方法或者臨時的活動時使用的方法,這時用混入會減少原始碼的汙染。

2、很多地方都會用到的公用方法,用混入的方法可以減少程式碼量,實現程式碼重用。

<h1>Mixins</h1>
  <hr>
  <div id="app">
    <p>num:{{ num }}</p>
    <P>
      <button @click="add">增加數量<tton>
    </P>
  </div>
  <script type="text/javascript">
    var addLog = { //額外臨時加入時,用於顯示日誌
      updated: function () {
        console.log("資料發生變化,變化成" + this.num + ".");
      }
    }
    Vue.mixin({// 全域性註冊一個混入,影響註冊之後所有建立的每個 Vue 例項
      updated: function () {
        console.log("我是全域性的混入")
      }
    })
    var app = new Vue({
      el: '#app',data: {
        num: 1
      },methods: {
        add: function () {
          this.num++;
        }
      },updated() {
        console.log("我是原生的update")
      },mixins: [addLog]//混入
    })

輸出的結果

vue 擴充套件現有元件的操作

mixins的呼叫順序

從執行的先後順序來說,混入物件的鉤子將在元件自身鉤子之前呼叫,如果遇到全域性混入(Vue.mixin),全域性混入的執行順序要前於混入和元件裡的方法。

2.使用extends 擴充套件

extends選項允許宣告擴充套件另一個元件,而無需使用 Vue.extend。

通過外部增加物件的形式,對構造器進行擴充套件。它和混入mixins非常的類似。只不過接收的引數是簡單的選項物件或建構函式,所以extends只能單次擴充套件一個元件。

var bbb = {
      updated() {
        console.log("我是被擴展出來的");
      },methods: {
        add: function () { //跟原生的方法衝突,取原生的方法,這點跟混入一樣
          console.log('我是被擴展出來的add方法!');
          this.num++;
        }
      }
    };
    var app = new Vue({
      el: '#app',methods: {
        add: function () {
          console.log('我是原生add方法');
          this.num++;
        }
      },updated() {
        console.log("我是擴展出來的");
      },extends: bbb// 接收物件和函式
    })

vue 擴充套件現有元件的操作

結果

執行的先後順序和mixins一樣,另外擴充套件的方法與原生的衝突時,擴充套件的方法不生效,這點跟混入一樣

ps extends和mixins優先順序比較

vue 擴充套件現有元件的操作

相對於mixins,extends觸發的優先順序更高

3.加slot擴充套件

.預設插槽和匿名插槽

slot用來獲取元件中的原內容,此方式用於父元件向子元件傳遞“標籤資料”。有的時候為插槽提供預設的內容是很有用的,例如,一個 元件可能希望這個按鈕的預設內容是“如果沒有原內容,則顯示該內容”,但是同時允許使用者覆寫為別的內容。

<body>
 <div id="itany">
  <my-hello>180812</my-hello>
 </div>
<template id="hello">
 <div>
  <h3>welcome to xiamen</h3>
  <slot>如果沒有原內容,則顯示該內容</slot>// 預設插槽
 </div>
</template>
<script>
 var vm=new Vue({
   el:'#itany',components:{
   'my-hello':{
   template:'#hello'
  }
   }
 });  
</script>

具名插槽

有些時候我們需要多個插槽,元素有一個特殊的特性:name。這個特性可以用來定義額外的插槽:

<div id="itany">
  <my-hello>
   <ul slot="s1">
  <li>aaa</li>
  <li>bbb</li>
  <li>ccc</li>
   </ul>
   <ol slot="s2">
  <li>111</li>
  <li>222</li>
  <li>333</li>
   </ol>
  </my-hello>
</div>
<template id="hello">
  <div>
   <slot name="s2"></slot>
   <h3>welcome to xiamen</h3>
   <slot name="s1"></slot>
  </div>
</template>
<script>
 var vm=new Vue({
  el:'#itany',components:{
   'my-hello':{
     template:'#hello'
    }
  }
 });  

補充知識:Vue extends拓展任意元件功能(el-select例項)-兩種寫法

用到ElementUI的select元件,要求能夠多選並且重複選擇。如果直接使用的話,首先el-tag會報錯,因為迴圈中key值重複;其次,他的移除是通過indexof搜尋移除的tag的值,且在remove-tag事件中未丟擲被移除tag的索引,這樣的後果是存在多個相同值的tag時,只會移除第一個相同值的tag

思路

在el-tag的迴圈中,給close事件增加一個引數index,然後重寫deleteTag方法,直接通過index刪除該tag

Vue: @close="deleteTag($event,item)"
JSX: on-close={e => this.deleteTag(e,this.selected[0])}
deleteTag(event,tag,tagIndex){
 const value = this.value.slice();
 value.splice(tagIndex,1);// 核心程式碼,其他程式碼省略
}

寫法一、Vue template(推薦)

非常簡單,改動特別少,可以使用Vue的所有用法,只需要複製el-select的template

新建一個vue檔案

複製el-select的template模板內容過來

匯入el-select,繼承

覆蓋methods中的deleteTag

結果

<template>
 <div
  class="el-select"
  :class="[selectSize ? 'el-select--' + selectSize : '']"
  @click.stop="toggleMenu"
  v-clickoutside="handleClose">
  我是示例程式碼,此處為自定義模板內容
 </div>
</template>

<script>
 import { Select} from 'element-ui';
 export default {
  extends: Select,//繼承
  name: 'my-el-select',methods: {
   deleteTag(event,tagIndex) {
// 重寫該方法
  },},};
</script>

寫法二、JSX(比較麻煩)

需要手動將Vue template轉為jsx寫法,無法使用事件修飾符,部分指令等等,改動比較大

1、匯入繼承

import {Select} from 'element-ui';

const myElSelect = {
 extends: Select
}

2、 重寫render

Vue template最終編譯之後也是生成render函式,這裡覆蓋render函式,

生成自定義內容。此處的意義只是為了記錄以便於方便我用render函式時的jsx寫法

render()
{
  const tagContent = () => {
   if (this.collapseTags && this.selected.length) {
    const tag0 = (
     <el-tag
      closable={!this.selectDisabled}
      size={this.collapseTagSize}
      hit={this.selected[0].hitState}
      type='info'
      on-close={e => this.deleteTag(e,this.selected[0])}
      disable-transitions={true}>
      <span class='el-select__tags-text'>{this.selected[0].currentLabel}</span>
     </el-tag>
    );
    const tag1 = (
     <el-tag
      closable={false}
      size={this.collapseTagSize}
      type='info'
      disable-transitions={true}>
      <span class='el-select__tags-text'>+ {this.selected.length - 1}</span>
     </el-tag>
    );

    if (this.selected.length > 1) {
     return (
      <span>
       {tag0}
       {tag1}
      </span>
     );
    }
    return (
     <span>
      {tag0}
     </span>
    );
   }
  };
  const emptyText = () => {
   if (this.emptyText && (!this.allowCreate || this.loading || (this.allowCreate && this.options.length === 0))) {
    return (
     <p class='el-select-dropdown__empty'>{this.emptyText}</p>
    );
   }
  };
  const selectOption = () => {
   return (
    <transition
     name='el-zoom-in-top'
     on-before-enter={this.handleMenuEnter}
     on-after-leave={this.doDestroy}>
     <el-select-menu
      ref='popper'
      append-to-body={this.popperAppendToBody}
      v-show={this.visible && this.emptyText !== false}>
      <el-scrollbar
       tag='ul'
       wrap-class='el-select-dropdown__wrap'
       view-class='el-select-dropdown__list'
       ref='scrollbar'
       class={{'is-empty': !this.allowCreate && this.query && this.filteredOptionsCount === 0}}
       v-show={this.options.length > 0 && !this.loading}>
       {this.showNewOption ? (
        <el-option
         value={this.query}
         created={true}>
        </el-option>
       ) : null}
       {
        this.$slots.default
       }
      </el-scrollbar>
      {emptyText()}
     </el-select-menu>
    </transition>
   );
  };
  return (
   <div
    class={['el-select',this.selectSize ? 'el-select--' + this.selectSize : '']}
    on-click={this.toggleMenu} v-clickoutside={this.handleClose}>
    <div
     class='el-select__tags'
     ref='tags'
     style={{'max-width': this.inputWidth - 32 + 'px'}}>
     {tagContent()}
     <transition-group onAfterLeave={this.resetInputHeight}>
      {this.selected.map((item,index) => {
       return (
        <el-tag
         key={index}
         closable={!this.selectDisabled}
         size={this.collapseTagSize}
         hit={item.hitState}
         type='info'
         on-close={(e) => this.deleteTag(e,item,index)}
         disable-transitions={false}>
         <span class='el-select__tags-text'>{item.currentLabel}</span>
        </el-tag>
       );
      })}
     </transition-group>
    </div>
    <el-input
     ref='reference'
     value={this.selectedLabel}
     type='text'
     placeholder={this.currentPlaceholder}
     name={this.name}
     id={this.id}
     auto-complete={this.autoComplete}
     size={this.selectSize}
     disabled={this.selectDisabled}
     readonly={this.readonly}
     validate-event={false}
     class={{'is-focus': this.visible}}
     on-focus={this.handleFocus}
     on-blur={this.handleBlur}
     on-keyup_native={this.debouncedOnInputChange}
     on-paste_native={this.debouncedOnInputChange}
     on-mouseenter_native={(this.inputHovering = true)}
     on-mouseleave_native={(this.inputHovering = false)}
    >
     <i slot='suffix'
       class={['el-select__caret','el-input__icon','el-icon-' + this.iconClass]}
       on-click={() => this.handleIconClick}/>
    </el-input>
    {selectOption()}
   </div>
  );
 }

3、 重寫method裡的deleteTag方法

4、結果

import {Select} from 'element-ui';

const myElSelect = {
 extends: Select,methods: {
  deleteTag(event,tagIndex) {
   // *****略
  },render() {
  return (
   <div>例子</div>
  );
 }
};
export default myElSelect;

以上這篇vue 擴充套件現有元件的操作就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。