vue2组件封装--隔山打牛

隔山打牛

顾名思义,就是隔着一层组件,中间封装的组件不动, 只动最底层组件和引用的组件, 这样子就做到了解耦,还可以把底层的值抛到引用组件, 处理我们想要的事务, 从而实现了组件的封装

背景

这是我做 avue-form 二开时碰到的一个问题,中间的一个组件(avue-form), 是使用了 avue 中间的插件, 下面是avue-form预览组件的核心代码:

ini 复制代码
  <el-drawer title="预览"
             :visible.sync="previewVisible"
             size="60%"
             append-to-body
             :before-close="handleBeforeClose">
    <avue-form v-if="previewVisible"
               ref="form"
               class="afd-preview-form"
               :option="option"
               v-model="form"
               @submit="handlePreviewSubmit"></avue-form>
    <div class="afd-drawer-foot">
      <el-button size="medium"
                 type="primary"
                 @click="handlePreviewSubmit">确定</el-button>
      <el-button size="medium"
                 type="danger"
                 @click="handleBeforeClose">取消</el-button>
    </div>
  </el-drawer>

而我自定义的组件也是挂载在avue-form里面的, 属于最底层,我想要上抛事件, 但我又不想去扩展第三方的插件, 我该怎么办? 第一个我想到的, 用event-bus吧, 这个随意在组件里面穿梭都可以, 但通过以往的经验, 这个方法是下下策, 因为后期这样子的代码根本没法维护, 就像我很少用minxin和provide一样, 这些都是实在没办法了才用。我下载了第三方avue源码,试图能得到些启发。

vue 复制代码
  <component :is="getComponent(column.type,column.component)"
             v-model="text"
             v-bind="Object.assign(column,$uploadFun(column))"
             v-on="event"
             :column="Object.assign(column,params)"
             :dic="dic"
             :box-type="boxType"
             ref="temp"
             :disabled="column.disabled || disabled"
             :readonly="column.readonly || readonly"
             :placeholder="getPlaceholder(column)"
             :props="column.props || props"
             :propsHttp="column.propsHttp || propsHttp"
             :size="column.size || size"
             :table-data="tableData"
             :type="type || column.type"
             :column-slot="columnSlot"
             @keyup.enter.native="enterChange">
    <span v-if="params.html"
          v-html="params.html"></span>
    <template slot-scope="scope"
              v-for="item in getSlotName(column,'T',$scopedSlots)?[column]:[]">
      <slot :name="getSlotName(item,'T')"
            v-bind="scope"></slot>
    </template>
    <template v-for="item in columnSlot"
              slot-scope="scope"
              :slot="item">
      <slot v-bind="scope"
            :name="item"></slot>
    </template>
  </component>

看到这里,我有点恼火,咱平常封装组件时,中间组件不都是写v-on="$listeners"和v-bind="$attrs" 么, 这样子最外层组件可以直接绑定值,传到最里层,最里面事件也可以上抛到最外层,我试着在底层自定义组件抛事件,外头啥都接不到!!!但v-on="event"是啥玩意??

能看出门道或者,这么用过的童鞋可以就不用往下看了,嗯,这篇文章就是解释这个v-on="event"的,没明白的,那么接着往下看:

js 复制代码
computed: {
    event () {
      return this.column.event || {}
    }
    }

它是一个computed计算属性,还是一个对象??

搞个demo,深度剖析

后面,我弄了个简单demo,照猫画虎,还真让抛事件成功了!!!上demo:

这里我有三个组件,three是孙组件,贴三个组件的代码后面再讲解耦原理

这是App的

vue 复制代码
<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <HelloWorld  :event='event' :msg="msg"/>
    <div>{{text}}</div>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
  name: 'App',
   data(){
    return {
     msg:'Welcome to Your Vue.js App',
     event:{
      agree:(val)=>{
        this.hello(val)
      }
     }
    }
  },
  methods:{
    hello(val){
      this.text=val
    }
  },
  components: {
    HelloWorld
  }
}
</script>

这是HelloWorld的

vue 复制代码
<template>
  <div class="hello">
    <h1 >{{ msg }}</h1>
   <three v-on='event' :msg='msg'></three>
  </div>
</template>

<script>
import three from './three.vue';
export default {
  name: 'HelloWorld',
  components:{
three  },
  props: {
    event:Object,
    msg: String
  },
    computed:{
   },
  methods:{
  }
}
</script>

这是three的

vue 复制代码
<template>
<button @click="click">dianji</button>
</template>

<script>
 export default {
   name:'ThreeSasdf',
 methods:{
  click(){
      this.$emit('agree','我是three的消息!')
    }
   }
 }
</script>

解析

这顿操作下来,我在app中真的把three中上抛的消息 '我是three的消息!' 给打印出来了!!也就是达到了,扩展组件three上抛事件,在app中定义

js 复制代码
` event:{
      agree:(val)=>{
        this.hello(val)
      },
      ....
     }`

这样子可以处理各种事务了,其中event是个对象,里面还可以继续定义其他很多的事件名,只要在孙组件中上抛了,那么祖组件event对应定义相应的名字接收,完美的略过了中间层helloword组件,达到了封装和解耦的目的!!其中需要注意的是,app中的this是指向app组件的,有兴趣的可以克隆该工程,地址如下:

如果各位感觉文字对你有帮助,请点击一个小小的赞,您的点赞是我继续创作的动力源泉!!

helloword git地址

相关推荐
腾讯TNTWeb前端团队1 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰5 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪5 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪5 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy6 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom6 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom6 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom7 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom7 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom7 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试