Vue自定義組件設(shè)計(jì)(ElementUI)

自定義ElementUI中form表單組件

如何去自定義組件呢?首先根據(jù)如何去使用組件來構(gòu)建組件掘宪,然后去實(shí)現(xiàn)每一個(gè)組件的細(xì)節(jié)寇钉。這里我們構(gòu)建一個(gè)自定義input組件,實(shí)現(xiàn)雙向數(shù)據(jù)綁定违寿。

項(xiàng)目目錄結(jié)構(gòu)

1湃交、環(huán)境使用vuecli3.0構(gòu)建的項(xiàng)目
2、實(shí)現(xiàn)思路
? ?2-1:首先通過使用elementUI的表單組件的結(jié)構(gòu)藤巢,構(gòu)建自定義表單組件結(jié)構(gòu)搞莺。
? ?2-2:從最里層開始實(shí)現(xiàn),首先實(shí)現(xiàn)input自定義組件掂咒。由于k-input使用了v-model才沧,在k-input組件中迈喉,需實(shí)現(xiàn)雙向數(shù)據(jù)綁定,綁定value温圆,監(jiān)聽input事件并分發(fā)挨摸。v-model的實(shí)現(xiàn)原理就是綁定value和監(jiān)聽input事件。
? ?2-3:表單校驗(yàn)需要安裝一個(gè)校驗(yàn)庫npm i async-validator

image.png

Index.vue

<template>
  <div>
    <h3>Element表單</h3>
    <!-- model rules 需要放到form組件上捌木,原因是內(nèi)層的form-item都需要使用 -->
    <k-form :model="model" :rules="rules" ref="loginForm">
      <k-form-item label="用戶名" prop="username">
        <k-input v-model="model.username" autocomplete="off" placeholder="請(qǐng)輸入用戶名"></k-input>
      </k-form-item>
      <k-form-item label="密碼" prop="password">
        <k-input v-model="model.password" type="password" autocomplete="off" placeholder="請(qǐng)輸入密碼"></k-input>
      </k-form-item>
      <k-form-item>
        <button @click="submitForm('loginForm')">提交</button>
      </k-form-item>
    </k-form>
  </div>
</template>

<script>
import KForm from "./KForm";
import KFormItem from "./KFormItem";
import KInput from "./KInput";
export default {
  components: {
    KForm,
    KFormItem,
    KInput
  },
  data() {
    return {
      model: {username:'',password:''},
      rules:{
        username:[{required:true,message:'請(qǐng)輸入用戶名'}],
        password:[{required:true,message:'請(qǐng)輸入密碼'}],
      }
    }
  },
  methods: {
    submitForm(form) {
      this.$refs[form].validate(valid => {
        if (valid) {
          alert("請(qǐng)求登錄");
        } else {
          alert("校驗(yàn)失敗");
        }
      });
    }
  }
};
</script>

<style lang="scss" scoped></style>

KInput.vue

<template>
  <div>
    <!-- 將k-input組件上的屬性展開放到input組件是 -->
    <input v-bind="$attrs" :value="value" @input="inputHandle">
  </div>
</template>

<script>
  export default {
    // 取消默認(rèn)將屬性放在div上
    inheritAttrs:false,
    props:{
      value:{
        type:String,
        default:''
      }
    },
    methods: {
      inputHandle(e) {
        // 分發(fā)k-input的input的事件油坝,實(shí)現(xiàn)雙向數(shù)據(jù)綁定
        this.$emit('input',e.target.value)
        // 分發(fā)校驗(yàn)事件 每次輸入框輸入了數(shù)據(jù)就就行校驗(yàn)
        this.$parent.$emit('validate')
      }
    },
  }
</script>

<style lang="scss" scoped>

</style>

KFormItem.vue

<template>
  <div>
    <label v-if="label">{{ label }}</label>
    <slot></slot>
    <p v-if="errorMsg">{{ errorMsg }}</p>
  </div>
</template>

<script>
import Schema from 'async-validator'
  export default {
    inject:['form'],
    props: {
      label: {
        type: String,
        default: ''
      },
      prop:{
        type:String
      }
    },
    data(){
      return {
        errorMsg:''
      }
    },
    mounted(){
      this.$on('validate',this.validate)
    },
    methods: {
      validate() {
        const value = this.form.model[this.prop]
        const rules = this.form.rules[this.prop]
        // 校驗(yàn)的描述對(duì)象
        const desc = {[this.prop]:rules}
        const schema = new Schema(desc)
        // 校驗(yàn)  return返回的是promise對(duì)象
        return schema.validate({[this.prop]:value},errors=>{
          if(errors){
            this.errorMsg = errors[0].message
          }else{
            this.errorMsg = ''
          }
        })
      }
    },
  }
</script>

<style lang="scss" scoped>

</style>

KForm.vue

<template>
  <div>
    <slot></slot>
  </div>
</template>

<script>
export default {
  provide() {
    return {
      form: this
    };
  },
  props: {
    model: {
      type: Object,
      required: true
    },
    rules: {
      type: Object
    }
  },
  methods: {
    validate(cb) {
      const tasks = this.$children
        .filter(item => item.prop)
        .map(item => item.validate());
      Promise.all(tasks)
        .then(() => cb(true))
        .catch(() => cb(false));
    }
  }
};
</script>

<style lang="scss" scoped></style>

自定義信息提示框組件

這類組件的特點(diǎn)在于,它們是獨(dú)立于當(dāng)前Vue實(shí)例之外獨(dú)立存在的刨裆,通常掛載在body上澈圈,是通過JavaScript動(dòng)態(tài)創(chuàng)建的,不需要在任何組件中聲明帆啃。

目錄結(jié)構(gòu)

image.png

KNotice.vue

<template>
  <div class="show-box" v-if="isShow">
    <h3>{{ title }}</h3>
    <p>{{ message }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      isShow: false
    }
  },
  props: {
    message: {
      type: String
    },
    title: {
      type: String
    },
    duration: {
      type: Number,
      default:1000
    }
  },
  methods: {
    show() {
      this.isShow = true
      setTimeout(this.hide, this.duration);
    },
    hide(){
      this.isShow = false
      this.remove() 
    }
  },
};
</script>

<style lang="scss" scoped>
  .show-box{
    position: absolute;
    top: 0;
    right: 0;
    left: 0;
    bottom: 0;
    margin: auto;
    width: 200px;
    height: 200px;
  }
</style>

Index.vue

<template>
  <div>
    <button @click="ShowHandle">顯示</button>
  </div>
</template>

<script>
import create from "../../utils/create";
import Notice from "./KNotice";
export default {
  methods: {
    ShowHandle() {
      const notice = create(Notice, {
        title: "校驗(yàn)成功",
        message: "你好牛逼哦",
        duration: 2000
      });
      notice.show()
    }
  }
};
</script>

<style lang="scss" scoped></style>

create.js

import Vue from "vue";
export default function create(Component, props) {
  // 創(chuàng)建Vue實(shí)例 先創(chuàng)建實(shí)例不掛載 直接將虛擬DOM掛載body上 會(huì)報(bào)錯(cuò)的
  const vm = new Vue({
    // 創(chuàng)建虛擬DOM 入?yún)ⅲ篶reateElement簡(jiǎn)寫為h
    render(h) {
      // h函數(shù)返回的是虛擬DOM
      return h(Component, { props });
    }
  }).$mount();
  // 手動(dòng)掛載  vm.$el是真實(shí)DOM
  document.body.appendChild(vm.$el)
  // 銷毀
  const comp = vm.$children[0]
  comp.remove = function(){
    // 移除DOM
    document.body.removeChild(vm.$el)
    // 銷毀組件
    vm.$destroy()
  }
  return comp
}

自定義樹形組件

目錄結(jié)構(gòu)

image.png

Item.vue

<template>
  <li>
    <div @click="toggle">
      {{ model.title }}
      <span v-if="isFolder">[{{ open ? "-" : "+" }}]</span>
    </div>
    <ul v-show="open" v-if="isFolder">
      <item
        class="item"
        v-for="model in model.children"
        :model="model"
        :key="model.id"
      ></item>
    </ul>
  </li>
</template>

<script>
export default {
  name: "Item",
  props: {
    model: {
      type: Object
    }
  },
  data() {
    return {
      open: false
    };
  },
  computed: {
    isFolder() {
      return this.model.children && this.model.children.length;
    }
  },
  methods: {
    toggle() {
      if (this.isFolder) {
        this.open = !this.open;
      }
    }
  }
};
</script>

<style lang="scss" scoped></style>

index.vue

<template>
  <div>
    <ul>
      <item :model="treeData"></item>
    </ul>
  </div>
</template>

<script>
import Item from "./Item";
export default {
  components: {
    Item
  },
  data() {
    return {
      treeData: {
        title: "web全棧架構(gòu)師",
        children: [
          {
            title: "java工程師",
            children: [
              {
                title: "python工程師"
              }
            ]
          },
          {
            title: "go工程師",
            children: [
              {
                title: "C#工程師"
              }
            ]
          }
        ]
      }
    };
  }
};
</script>

<style lang="scss" scoped></style>

效果圖
image.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瞬女,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子努潘,更是在濱河造成了極大的恐慌诽偷,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疯坤,死亡現(xiàn)場(chǎng)離奇詭異报慕,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)压怠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門眠冈,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人菌瘫,你說我怎么就攤上這事蜗顽。” “怎么了雨让?”我有些...
    開封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵雇盖,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我栖忠,道長(zhǎng)崔挖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任庵寞,我火速辦了婚禮虚汛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘皇帮。我一直安慰自己卷哩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開白布属拾。 她就那樣靜靜地躺著将谊,像睡著了一般冷溶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上尊浓,一...
    開封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天逞频,我揣著相機(jī)與錄音,去河邊找鬼栋齿。 笑死苗胀,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的瓦堵。 我是一名探鬼主播基协,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼菇用!你這毒婦竟也來了澜驮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤惋鸥,失蹤者是張志新(化名)和其女友劉穎杂穷,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體卦绣,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡耐量,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了滤港。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拴鸵。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蜗搔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情八堡,我是刑警寧澤樟凄,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站兄渺,受9級(jí)特大地震影響缝龄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜挂谍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一叔壤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧口叙,春花似錦炼绘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽驮捍。三九已至,卻和暖如春脚曾,著一層夾襖步出監(jiān)牢的瞬間东且,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工本讥, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留珊泳,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓拷沸,卻偏偏與公主長(zhǎng)得像色查,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子堵漱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

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