更好的封装vue组件

180 阅读2分钟

更好的封装vue组件

我给组件分类

  • 单向组件

    组件只关心数据的展示和事件挂载;单纯的数据展示组件。

  • 双向组件

    响应式组件,组件除了展示父组件传入数据的之外,在组件中可能会有点击,输入等操作筛选期望数据返回给父组件。

  • API组件

    适合单独的API调用方式调用,如提示框、弹出框之类的

  • 高阶组件

    组件嵌套超过两次

单向组件

  • 场景一:仅仅用作展示

    比较简单,利用vue的props特性即可;有需要的情况下可以利用computed计算属性对prop的值进行转化展示。

  • 场景二:初始化展示,即可能会变动但不改动数据源

    prop的值用作初始化,应该定义子组件的data属性并将prop作为其初始值。

  • 场景三:""跨多代"的数据传递

    利用v$attrs特性

    • 高级别的组件时非常有用

    • uniapp不支持

    • 包括了classstyle 除外的所有属性

    • Vue会将组件被传入但未声明的Prop当做Html属性绑定到根元素上;

      解决:设置inheritAttrs 为 false,

 // 父组件
 <template>
     <chlid :data1="'1223'" :data2="'1232'" />
 </template>
 ​
 //子组件chlid
 <template>
     <view>
         <view>这是child组件</view>
         <view>{{$attrs.data1}}</view>
       <view>{{$attrs.data2}}</view>
      <Sun v-bind="$attrs"  />
     </view>
 </template>
 ​
 //孙组件Sun
 <template>
     <view>
         <view >这是Sun组件{{$attrs.data1}}</view>
     </view>
 </template>
 <script>
     export default {
         inheritAttrs: false,
     }
 </script>

双向组件

  • 场景一:表单输入类型不满足需求,自定义表单输入、表单选择

v-model做了两件事:

  1. 将value属性值与变量值绑定(等价于:
    ),并将value作为返回值抛出input事件(等价于:this.$emit('input',value))
  2. 将input事件的返回值重新赋予变量(等价于:<div :value="variable" @input="(value)=>{ this.variable = value }" />)

API组件

  • 场景一:使用频繁,风格规范统一

    extend$mount

    本质上是将实例化方法挂载到vue的原型上,调用时执行实例化方法,将组件append到body当中,完成组件的渲染。

     // alert.js
     import vue from "vue';
     import alertTips from ' . /alertTips .vue';
     ​
     const TipsConstructor = vue.extend(alertTips);
     ​
     //使用这个方法调用alertTips组件
     function showTips(options) {
         options = options || {};
         // 简单的参数处理  
         if( typeof options==="object" ){
         options = {
             text: options.text,//提示文字
         }else{
             new Error('传参格式不对")
         }
                       
     //实例化子组件,然后获取到DOM结构并挂载到body上
     const tipsInstence = new TipsConstructor({data: options});
         
     let timer;
     tipsInstence .vm = tipsInstence .$mount():
     //将实例化后的组件通过appendchild方法挂载到页面上
     document .getElementById( "app").appendChild(tipsInstence.vm.$el);
         
     timer = setTimeout(function(){
         //1500毫秒后通过removeChild方法将组件移除
         document .getElementById( 'app').removechild(tipsInstence vm.$el);
         clearTimeout(timer);
         },1500)
     }
     export default showTips;
    

    使用

     import alert from './alert.js'
     // 挂载到Vue原型上
     Vue.prototype.$Alert = alert
     // 然后在组件中使用
     this.$Alert.showTips({text: '提示'})
    

高阶组件

  • 场景一:假设最外层是父组件,抽屉组件为子组件,抽屉内容为孙组件。现在我们要新增一个父组件,父组件的抽屉内容是表单或者是其他全新的内容,抽屉组件保持不变。如何封装这个抽屉?

image-20220827151218254.png

渲染函数vue组件

利用渲染函数,让子组件渲染自定义的内容(孙组件),而自定义的内容由父组件传入。

父组件调用抽屉

 // 部分代码
 <template>
     <AgDrawer
       :visible.sync="agDrawerData.visible"  // 是否显示抽屉
       :drawer="agDrawerData" // 抽屉的内容
       @onDrawerAction="onAgDrawerAction" // 处理抽屉事件
     />
 </template>
 <script>
   import DecorationOrderForm from "@/pages/DecorationOrderForm";
    export default {
        data(){
            return {
                agDrawerData: {
               action: 'test',
                component: DecorationOrderForm,
                preload: {title: '编辑'},
                drawerStyle: {
                drawerClass: 'ag-drawer-mid-class'
                }
            }
        }
    } 
 </script>

抽屉传递数据,处理抽屉的其他逻辑

 // 部分代码
 <template>
   <el-drawer
     :visible.sync="inVisible"
     :show-close="drawerStyle.showClose"
     :append-to-body="drawerStyle.appendToBody"
     :close-on-press-escape="drawerStyle.closeOnPressEscape"
     :close-on-click-moda="drawerStyle.closeOnClickModal"
     :withHeader="false"
     :custom-class="drawerStyle.drawerClass"
     :direction="drawerStyle.direction">
     <ag-drawer-body @onDrawerClose="onDrawerClose" @onDrawerAction="onDrawerAction" v-if="inVisible"
                     :drawer="drawer"></ag-drawer-body>
   </el-drawer>
 </template>

孙组件渲染内容

 <script>
 export default {
   name: 'AgDrawerBody',
   props: {
     drawer: {type: Object, default:{}},
   },
   render(createElement) {
     if (this.drawer.component){
       return createElement(this.drawer.component,{
         props:{
           drawer:this.drawer
         },
       })
     }
     return createElement('h1',`action:${this.action}未设置drawer`)
   },
   created() {
   }
 }
 </script>
 ​


最后一句

这是沉曦的学习心得!若有不正,还望斧正。希望掘友们不要吝啬对我的建议哦,回见。