vue封裝一個(gè)可處理表單的組件

一份氧、需求。

最近在開(kāi)發(fā)一個(gè)新系統(tǒng)弯屈,有很多功能以及表單需要處理半火,為了偷懶,想著封裝一個(gè)組件統(tǒng)一處理下相關(guān)邏輯季俩,這樣下來(lái)钮糖,每個(gè)功能只需寫(xiě)一個(gè)列表查詢(xún)的組件和一個(gè)表單組件,省時(shí)省心。
最終效果:


最終效果圖

二店归、需要實(shí)現(xiàn)的點(diǎn):

1阎抒、 增加、修改消痛、查看三個(gè)功能都在這里進(jìn)行處理
2且叁、每個(gè)功能只需要寫(xiě)好表單以及對(duì)應(yīng)事件,用該組件統(tǒng)一處理外部樣式以及觸發(fā)子組件中的表單事件(這里的表單作為子組件)
3秩伞、因?yàn)橛凶髠?cè)邊欄的緣故逞带,還需要?jiǎng)討B(tài)調(diào)整寬度

三、具體實(shí)現(xiàn)

<!--基于element封裝的抽屜組件纱新,具體api見(jiàn):https://element.eleme.io/#/zh-CN/component/drawer-->
<template>
  <div>
    <el-drawer ref="drawer"
               append-to-body
               :size="drawer.width"
               :before-close="beforeClose"
               :visible="drawer.show"
               :direction="direction"
               :destroy-on-close="destroy"
               :wrapperClosable="wrapperClosable"
               @open="getNewWidth"
               @close="closeHander">
      <!-- 標(biāo)題部分 -->
      <template slot="title">
        <p>{{ titleText }}</p>
      </template>
      <!-- 主要內(nèi)容 -->
      <slot name="main"></slot>
      <div class="drawer__footer">
        <Button size="large"
                icon="md-close"
                @click="CloseDrawer">{{
          showSubmitBtn ? "取消" : "關(guān)閉"
        }}</Button>
        <Button v-if="showSubmitBtn"
                size="large"
                type="primary"
                @click="submit"
                icon="md-checkbox-outline"
                :loading="loading">{{ loading ? "提交中 ..." : "確 定" }}</Button>
      </div>
    </el-drawer>
  </div>
</template>
<script>
export default {
  name: 'JcDrawer',
  props: {
    //模式:1新增  2修改  3查看
    mode: {
      default: 1,
      type: Number,
    },
    //是否顯示
    show: {
      default: false,
    },
    //標(biāo)題
    title: {
      type: String,
    },
    //打開(kāi)方向
    direction: {
      default: 'rtl',
      type: String,
    },
    //控制是否在關(guān)閉 Drawer 之后將子元素全部銷(xiāo)毀
    destroy: {
      default: true,
      type: Boolean,
    },
    //點(diǎn)擊遮罩層是否可以關(guān)閉 Drawer
    wrapperClosable: {
      default: false,
      type: Boolean,
    },
    //是否顯示提交按鈕(有的界面無(wú)需提交)
    showSubmitBtn: {
      default: true,
      type: Boolean,
    },
  },
  data() {
    return {
      isAuto: false, // 是否自動(dòng)關(guān)閉
      Bus: this.$BusFactory(this),
      loading: false,
      drawer: {
        width: 0,
        show: this.show,
        mode: this.mode,
      },
    }
  },
  mounted() {
    //初始化完成時(shí)添加一個(gè)事件用于監(jiān)聽(tīng)屏幕大小變化展氓,自適應(yīng)調(diào)整寬度
    window.onresize = () => {
      return (() => {
        this.getNewWidth()
      })()
    }
  },

  watch: {
    //監(jiān)聽(tīng)父組件的值控制是否顯示
    show: {
      immediate: true,
      deep: true,
      handler(newvalue, oldvalue) {
        this.drawer.show = newvalue
      },
    },
    mode: {
      immediate: true,
      handler(newvalue, oldvalue) {
        this.drawer.mode = newvalue
      },
    },
  },
  computed: {
    /**
     * @description 標(biāo)題
     */
    titleText() {
      if (this.drawer.mode === 1) return `添加${this.title}信息`
      if (this.drawer.mode === 2) return `修改${this.title}信息`
      if (this.drawer.mode === 3) return `查看${this.title}信息`
    },
  },
  methods: {
    /**
     * @description 關(guān)閉之后的事件
     */
    closeHander() {
      //取消自動(dòng)關(guān)閉
      this.isAuto = false
    },
    /**
     * @description 關(guān)閉窗口
     */
    CloseDrawer() {
      if (this.showSubmitBtn) {
        this.isAuto = false
      } else {
        this.isAuto = true
      }
      this.$refs.drawer.closeDrawer()
    },

    /**
     * @description 關(guān)閉抽屜的事件
     * @param {function} done 關(guān)閉的回調(diào)
     */
    beforeClose(done) {
      if (!this.isAuto && this.showSubmitBtn) {
        this.$confirm('確定要關(guān)閉嗎?', '提示', {
          confirmButtonText: '確定',
          cancelButtonText: '取消',
          type: 'warning',
        }).then((_) => {
          this.$emit('close')
          done()
        })
      } else {
        this.$emit('close')
        done()
      }
    },
    //提交事件
    submit(callback) {
      var that = this
      that.loading = true
      if (this.drawer.mode == 1) {
        //使用事件總線(xiàn)的方式觸發(fā)表單組件中的事件
        this.Bus.$emit('Add', function (res) {
          if (res.success) {
            that
              .$confirm('添加成功脸爱!', '提示', {
                confirmButtonText: '確定',
                showCancelButton: false,
                type: 'success',
                closeOnClickModal: false,
                closeOnPressEscape: false,
                showClose: false,
              })
              .then(() => {
                //點(diǎn)擊確認(rèn)之后直接退出并銷(xiāo)毀表單
                that.isAuto = true
                that.$refs.drawer.closeDrawer()
              })
          }
        })
      }
      if (this.drawer.mode == 2) {
        this.Bus.$emit('Edit', function (res) {
          if (res.success) {
            that
              .$confirm('修改成功遇汞!', '提示', {
                confirmButtonText: '確定',
                showCancelButton: false,
                type: 'success',
                closeOnClickModal: false,
                closeOnPressEscape: false,
                showClose: false,
              })
              .then(() => {
                that.isAuto = true
                that.$refs.drawer.closeDrawer()
              })
          }
        })
      }
      if (this.drawer.mode == 3) {
        this.Bus.$emit('Detail', function () {
          that.isAuto = true
          that.$refs.drawer.closeDrawer()
        })
        that.loading = false
      }
    },
    /**
     * @description 設(shè)置主界面的寬度
     */
    getNewWidth() {
      //組件寬度=當(dāng)前屏幕寬度-側(cè)邊欄寬度
      this.drawer.width =
        document.body.clientWidth -
        (parseInt(document.getElementById('left_nav')?.style?.width) || 0)
    },
  },
}
</script>
<style scoped>
.drawer__footer {
  width: 100%;
  border-top: 1px solid #e8eaec;
  position: absolute;
  bottom: 0;
  padding: 10px;
  display: flex;
  justify-content: center;
  background-color: white;
  z-index: 99;
}
.drawer__footer button {
  margin: 0 10px;
}
</style>

使用(列表查詢(xún)組件):

<!--列表組件-->
<template>
  <!--...列表展示內(nèi)容-->
  <jc-drawer :show="formShow"
             @close="formShow = false"
             :title="title"
             :mode="mode">
    <!-- 使用插槽插入表單 -->
    <template slot="main">
      <role-form :roleId="roleId"
                 @getList="getList"
                 :mode="mode"></role-form>
    </template>
  </jc-drawer>
</template>
<script>
import jcDrawer from '@/components/jc-cpn/jc-drawer.vue'
import RoleForm from './form'
export default {
  components: { jcDrawer, RoleForm },
  name: 'role',
  data() {
    return {
      roleId: null,
      mode: 1,
      title: '角色',
      formShow: false,
    }
  },

  methods: {
    // 添加角色
    roleAdd() {
      this.mode = 1
      this.formShow = true
    },
    //編輯角色
    roleEdit() {
      this.mode = 2
      this.roleId = 點(diǎn)擊編輯按鈕時(shí)行的id
      this.formShow = true
    },
    //查看角色
    roleDetail() {
      this.mode = 3
      this.roleId = 點(diǎn)擊查看按鈕時(shí)行的id
      this.formShow = true
    },
  },
}
</script>

表單組件:

<!-- 角色的form表單 -->
<template>
  <div>
    <!-- 表單元素 -->
  </div>
</template>
<script>
export default {
  name: 'RoleForm',
  props: {
    roleId: {
      type: Number,
      default: null,
    },
    mode: {
      type: Number,
      default: 1,
    },
  },
  data() {
    return {
      // 事件總線(xiàn)實(shí)例。詳情見(jiàn):https://zhuanlan.zhihu.com/p/32029461
      Bus: this.$BusFactory(this),
      loading: false,
    }
  },
  watch: {
    //監(jiān)聽(tīng)父組件的值控制是否顯示
    roleId: {
      immediate: true,
      deep: true,
      handler(newvalue, oldvalue) {
        if (this.mode == 2) {
          //回填數(shù)據(jù)
          this.setCurrentData()
        }
      },
    },
  },
  mounted() {
    //采用事件總線(xiàn)的方式綁定drawer組件中定義的方法簿废,采用事件回調(diào)的方式通知drawer此次事件的完成情況空入,在drawer中統(tǒng)一處理
    //新增方法
    this.Bus.$on('Add', (callback) => {
      this.RoleAdd(callback)
    })
    //新增方法
    this.Bus.$on('Edit', (callback) => {
      this.RoleEdit(callback)
    })
  },
  methods: {
    /**
     * @description 角色添加
     * @param {function} callback 回調(diào)函數(shù),請(qǐng)求完成后用于通知抽屜組件完成狀態(tài)
     */
    RoleAdd(callback) {
      callback(...res)
    },
    /**
     * @description 角色修改
     * @param {function} callback 回調(diào)函數(shù)族檬,請(qǐng)求完成后用于通知抽屜組件完成狀態(tài)
     */
    RoleEdit(name, callback) {
      callback(...res)
    },
  },
}
</script>

最終目錄結(jié)構(gòu)
總結(jié):完成這樣一套邏輯之后歪赢,對(duì)應(yīng)功能節(jié)點(diǎn)只需要完成如圖表單組件和列表查詢(xún)組件,而且表單中只需處理數(shù)據(jù)单料,提示或者報(bào)錯(cuò)都放到drawer組件中進(jìn)行處理轨淌,極大程度上保護(hù)了自己的頭發(fā)。

另:有關(guān)事件總線(xiàn)不明白的地方可參考:Vue自動(dòng)銷(xiāo)毀的vue event Bus看尼。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市盟步,隨后出現(xiàn)的幾起案子藏斩,更是在濱河造成了極大的恐慌,老刑警劉巖却盘,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件狰域,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡黄橘,警方通過(guò)查閱死者的電腦和手機(jī)兆览,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)塞关,“玉大人抬探,你說(shuō)我怎么就攤上這事。” “怎么了小压?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵线梗,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我怠益,道長(zhǎng)仪搔,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任蜻牢,我火速辦了婚禮烤咧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘抢呆。我一直安慰自己煮嫌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布镀娶。 她就那樣靜靜地躺著立膛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪梯码。 梳的紋絲不亂的頭發(fā)上宝泵,一...
    開(kāi)封第一講書(shū)人閱讀 51,182評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音轩娶,去河邊找鬼儿奶。 笑死,一個(gè)胖子當(dāng)著我的面吹牛鳄抒,可吹牛的內(nèi)容都是我干的闯捎。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼许溅,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼瓤鼻!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起贤重,我...
    開(kāi)封第一講書(shū)人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤茬祷,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后并蝗,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體祭犯,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年滚停,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了沃粗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡键畴,死狀恐怖最盅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤檩禾,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布挂签,位于F島的核電站,受9級(jí)特大地震影響盼产,放射性物質(zhì)發(fā)生泄漏饵婆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一戏售、第九天 我趴在偏房一處隱蔽的房頂上張望侨核。 院中可真熱鬧,春花似錦灌灾、人聲如沸搓译。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)些己。三九已至,卻和暖如春嘿般,著一層夾襖步出監(jiān)牢的瞬間段标,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工炉奴, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留逼庞,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓瞻赶,卻偏偏與公主長(zhǎng)得像赛糟,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子砸逊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

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