Vue3組件(三)把別人的組件拿過來再封裝一下

胡一菲說過,做巧克力很簡單嘛,把商場里賣的巧克力買回來,融化后加點(diǎn)葡萄干、干果,然后再造型、凝固——巧克力就做好了。

是不是超簡單?
是的,在開源世界里面就是這么簡單,我們完全可以在開源的UI庫的基礎(chǔ)上實(shí)現(xiàn)自己的想法。

那么為啥要進(jìn)行二次封裝呢?

  • 便于切換UI庫。
  • 可以應(yīng)對版本升級。
  • 可以循環(huán)綁定控件。
  • 折騰后自己用著舒服。

定義“接口”

一般UI庫都會提供一些列的控件,比如form分類下面的控件,就可以有十多個(gè),那么要封裝的話,首先就要確定接口,否則只能封裝個(gè)寂寞。

簡潔期間,定義兩個(gè)屬性,一個(gè)事件。

  • modelValue
    綁定控件值的,類型可以是string、number、數(shù)組等。

  • meta
    統(tǒng)一存放控件需要的各種屬性,也可以包括回調(diào)函數(shù)。

  • input
    大多數(shù)情況都可以用input事件,各個(gè)的需要change等事件,不過事件比較寬松,可以靈活設(shè)定。

這里的接口并不是面向?qū)ο蟮慕涌冢矝]有用TypeScript那樣的接口,而是一種約定和協(xié)議。原則上做限定,但是實(shí)際上還是可以放飛自我。

定義共用方法

vue2.x的時(shí)候需要使用mixin的方式,到了vue3.x 可以使用更靈活的方式來實(shí)現(xiàn)共用函數(shù)的目的。

inputManage

import { ref, watch } from 'vue'

const inputManage = (props, context) => {
 // 綁定控件的值
 const value = ref('')

 // 監(jiān)聽屬性,給 value 賦值
 watch(() => props.modelValue, (v1, v2) => {
   value.value = v1
 })

 // 向父組件提交事件
 const myInput = (e) => {
   context.emit('update:modelValue', e)
   context.emit('input', e)
 }

 return {
   value,
   myInput
 }
}

export default inputManage
  • 管理類的參數(shù)
    因?yàn)橐玫浇M件的屬性和emit,所以需要設(shè)置兩個(gè)參數(shù)來接收組件傳遞過來的屬性和emit。

首先用 import 導(dǎo)入需要的方法,然后定義一個(gè)用于綁定控件的值 value——ref類型的——用著方便。
然后設(shè)置一個(gè) watch 監(jiān)控屬性變化,然后給value賦值。
最后設(shè)計(jì)一個(gè)提交的函數(shù)。

基本設(shè)定就是這樣,以后可以根據(jù)需求在完善,比如增加 blur 事件的提交,表單驗(yàn)證的時(shí)候可能會用到。

為啥不把組件的屬性直接綁定到控件的value?一開始我就是直接綁定的,結(jié)果出錯了。研究之后發(fā)現(xiàn),element-plus把原生的value給覆蓋了,變成了和 v-model 一樣的屬性了,這樣就不能直接綁定組件的屬性了。所以很無奈的做了一個(gè)內(nèi)部的轉(zhuǎn)換。

config

const metaInput = {
  type: Object,
  default: () => {
    return {
      // 通用
      controlId: Number, // 編號,區(qū)別同一個(gè)表單里的其他控件
      colName: String, // 字段名稱
      controlType: Number, // 用類型編號表示type
      isClear: {
        // isClear  連續(xù)添加時(shí)是否恢復(fù)默認(rèn)值
        type: Boolean,
        default: false
      },
      defaultValue: String, // 默認(rèn)值
      autofocus: { // 是否自動獲得焦點(diǎn)
        type: Boolean,
        default: false
      },
      disabled: {
        // 是否禁用
        type: Boolean,
        default: false
      },
      required: { // 必填
        type: Boolean,
        default: true
      },
      readonly: { // 只讀
        type: Boolean,
        default: false
      },
      pattern: String, // 用正則做驗(yàn)證。
      class: {
        type: String,
        default: 'ant-input ant-input-sm'
      },
      placeholder: String,
      title: String, // 提示信息
      size: Number, // 字符寬度
      maxlength: Number, // 最大字符數(shù)
      autocomplete: { // off
        type: String,
        default: 'on'
      },
      optionKey: String, // 備選文字標(biāo)識
      optionItem: Object // 備選的選項(xiàng)
    }
  }
}

export default {
  metaInput
}

這個(gè)是控件需要的屬性的說明和驗(yàn)證。這么長的代碼,當(dāng)然要放在獨(dú)立的地方了。

逐一封裝控件

然后就是辛苦活了,一個(gè)一個(gè)封裝唄,這里舉一個(gè)例子就好,不一一貼代碼了。

text 單行文本

<!--單行文本-->
<template>
  <el-input
    v-model="value"
    @input="myInput"
    :rows="12"
    :autosize="{ minRows: 3, maxRows: 6 }"
    :show-word-limit="true"
    :maxlength="meta.maxlength"
    :placeholder="meta.placeholder"
  >
  </el-input>
</template>

<script>
import inputManage from '../manage/inputManage.js'
import { metaInput } from '../manage/config.js'

export default {
  name: 'nf-textarea',
  props: {
    modelValue: String,
    meta: metaInput
  },
  emits: ['input', 'change', 'blur', 'focus', 'clear'],
  setup (props, context) {
    const { value, myInput } = inputManage(props, context)

    return {
      value,
      myInput
    }
  }
}
</script>

  • template
    按照控件需要的屬性,一個(gè)一個(gè)綁好。

  • js代碼
    因?yàn)榘压灿玫牟糠侄继崛〕鋈チ耍孕枰獙懙拇a就非常少了。
    定義兩個(gè)屬性,屬性的具體定義放在共用函數(shù)里面,這里就很簡潔了。

setup里面就是獲取變量和方法,然后return就可以了。

其難點(diǎn)就是如何處理控件需要的各種屬性,需要一個(gè)一個(gè)綁定好,這是一個(gè)辛苦活,需要一個(gè)一個(gè)對照。

有些屬性還需要做一些轉(zhuǎn)換。不過都搞定后,以后用著就非常方便了。

復(fù)選組

<!--多選組-->
<template>
  <el-checkbox-group v-model="checks" @change="myInput">
    <el-checkbox :label="3">備選項(xiàng)</el-checkbox>
    <el-checkbox :label="6">備選項(xiàng)</el-checkbox>
    <el-checkbox :label="9">備選項(xiàng)</el-checkbox>
  </el-checkbox-group>
</template>
import inputManage from '../manage/inputManage.js'
import { metaInput } from '../manage/config.js'
import { ref } from 'vue'

export default {
  name: 'nf-el-from-checkbox',
  props: {
    modelValue: String,
    meta: metaInput
  },
  emits: ['input', 'change', 'blur', 'focus', 'clear'],
  setup (props, context) {
    const { value, myInput } = inputManage(props, context)

    const checks = ref([])

    return {
      value,
      myInput,
      checks
    }
  }
}

這個(gè)稍微有點(diǎn)不同,因?yàn)榭丶闹挡皇莝tring,而是一個(gè)數(shù)組,所以需要單獨(dú)設(shè)置一個(gè)數(shù)組來中轉(zhuǎn)一下。

如果組件有不同的需求,稍微做點(diǎn)修改就好。實(shí)在不行重做一個(gè)也行。js就是比較隨意。。。

其他的就不一一貼了,大同小異。

表單頁面里使用控件

都封裝好了,那么如何使用呢?

首先要引用進(jìn)來,然后設(shè)置屬性就可以了,比如這樣。

    <el-form ref="form" :model="model" label-width="80px">
      <el-form-item label="活動名稱">
        <eltext v-model="model.name" :meta="metaText"/>
      </el-form-item>
      <el-form-item label="活動網(wǎng)址">
        <elurl v-model="model.url" :meta="metaText" @input="myChange"/>
      </el-form-item>
      <el-form-item label="年齡要求">
        <elnumber v-model="model.age" :meta="metaText" @input="myChange"/>
      </el-form-item>
      <el-form-item label="年齡要求">
        <elrange v-model="model.age" :meta="metaText" @input="myChange"/>
      </el-form-item>
      <el-form-item label="活動區(qū)域">
        <elselect v-model="model.select" :meta="metaText" @input="myChange"/>
      </el-form-item>
      <el-form-item label="活動日期">
        <eldate v-model="model.date" :meta="metaText" @input="myChange"/> -
        <eltime v-model="model.time" :meta="metaText" @input="myChange"/>
      </el-form-item>
      <el-form-item label="即時(shí)配送">
        <elradios v-model="model.radio" :meta="metaText" @input="myChange"/>
      </el-form-item>
      <el-form-item label="活動性質(zhì)">
        <elcheckbox v-model="model.checks" :meta="metaText" @input="myChange"/>
      </el-form-item>
      <el-form-item label="特殊資源">
        <elswitch v-model="model.switch" :meta="metaText" @input="myChange"/>
      </el-form-item>
      <el-form-item label="活動形式">
        <elarea v-model="model.contact" :meta="metaText" @input="myChange"/>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="onSubmit">立即創(chuàng)建</el-button>
        <el-button>取消</el-button>
      </el-form-item>
    </el-form>

本來寫了一個(gè)el-row版本的,但是代碼太長,直接寫el-form版的吧。

import { reactive } from 'vue'
import eltext from '@/components/nf-el-form/input-text.vue'
import elarea from '@/components/nf-el-form/textarea.vue'
import elurl from '@/components/nf-el-form/url.vue'
import elnumber from '@/components/nf-el-form/input-number.vue'
import elrange from '@/components/nf-el-form/input-range.vue'
import eldate from '@/components/nf-el-form/input-date.vue'
import eltime from '@/components/nf-el-form/input-time.vue'
import elradios from '@/components/nf-el-form/radios.vue'
import elcheckbox from '@/components/nf-el-form/checkbox.vue'
import elselect from '@/components/nf-el-form/select.vue'
import elswitch from '@/components/nf-el-form/switch.vue'

export default {
  name: 'eleBase',
  components: {
    eltext,
    elarea,
    elurl,
    elnumber,
    elrange,
    eldate,
    eltime,
    elradios,
    elcheckbox,
    elselect,
    elswitch

  },
  setup () {
    // 定義表單實(shí)體類
    const model = reactive({
      age: 1,
      url: '',
      name: '',
      contact: '',
      date: null,
      time: null,
      radio: 1,
      checks: [],
      select: 1,
      switch: true

    })

    // 定義樣式
    const formTitleStyle = {
      'text-align': 'right',
      'padding-right': '10px'
    }

    // 控件類型的屬性
    const metaText = reactive({
      controlId: 103,
      colName: 'controlType',
      controlType: 190,
      optionList: [],
      isClear: false,
      disabled: false,
      required: true,
      pattern: '',
      title: '組件類型',
      placeholder: '請輸入組件類型',
      maxlength: 100,
      readonly: false
    })

    const myChange = (e) => {
      // alert(e)
      console.log('changele')
    }

    return {
      model,
      formTitleStyle,
      metaText,
      myChange
    }
  }
}

首先是注冊組件,然后定義組件需要的屬性,然后return就可以了。

能不能簡化?

當(dāng)然可以了,這樣的代碼對于我這么懶的人,還是太麻煩了。
那么如何簡化呢?這個(gè)有很多種方法,比如v-for,比如做一個(gè)單獨(dú)的表單組件。

總之方法有很多,具體方法,下次再說。

先看看效果圖:


004表單效果.png

看圖是不是感覺沒啥特別的,這個(gè)嘛看效果當(dāng)然沒啥特別的了,關(guān)鍵是代碼如何實(shí)現(xiàn)的,你說對不。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,321評論 6 543
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,559評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,442評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,835評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,581評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,922評論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,931評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,096評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,639評論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,374評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,591評論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,104評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,789評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,196評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,524評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,322評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,554評論 2 379

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