Vue 动态组件 以及 如何动态挂载组件

业务场景,实现向导页面,每个向导对应一个vue组件。由于向导信息和vue组件名称在表里存储所以页面上要完全动态渲染。

**组件挂载到VUE上**
在这里插入图片描述
在这里插入图片描述
结构
在这里插入图片描述
在这里插入图片描述

完整代码:

<template>
  <div class="body">
    <div class="header">
      <a-row>
        <a-col :span="3">
          <span>客户编号:{
   
   {  }}</span>
        </a-col>
        <a-col :span="5">
          <span>客户名称:{
   
   {  }}</span>
        </a-col>
        <a-col :span="3">
          <span></span>
        </a-col>
        <a-col :span="3">
          <span></span>
        </a-col>
        <a-col :span="4">
          <span></span>
        </a-col>
        <a-col :span="3">
          <span></span>
        </a-col>
        <a-col :span="3">
          <span></span>
        </a-col>
      </a-row>
    </div>
    <div class="sider">
      <div style="height: 90%;">
        <a-steps v-model="step" direction="vertical" :disabled="true">
          <a-step
            v-for="item in wizard"
            :title="item.WKFL_STEP_NAME"
            :key="item.WKFL_STEP_SEQ"
            :description="item.WKFL_STEP_DESC"
            :disabled="true"
          />
        </a-steps>
      </div>
      <div style="height: 10%;">
        <div>
          <div style="float:left;">
            <a-button style="width: 74px;" @click="lastStep" v-show="lastBtnVisible">{
   
   { lastText }}</a-button>
          </div>
          <div style="float:right;">
            <a-button style="width: 74px;" @click="nextStep" type="primary">{
   
   { nextText }}</a-button>
          </div>
        </div>
      </div>
    </div>
    <div class="content">
      <keep-alive>
        <component ref="child" :is="component" :param="param" :step="step"></component>
      </keep-alive>
    </div>
  </div>
</template>
<script>
import Vue from 'vue'
import {
      
       qryWkflWizardList, qryRatingResultList, getDeptNoByEmpeNo } from '@/api/api'
export default {
      
      
  data () {
      
      
    return {
      
      
      component: null,
      step: 0,
      wizard: [],
      lastText: '<上一步',
      nextText: '下一步>',
      lastBtnVisible: false,
      parentQuery: this.$route.query,
      ratingResult: {
      
      },
      dict: {
      
      },
      param: {
      
      
        custId: '',
        custName: '',
        modelId: '',
        modelName: '',
        modelVersn: '',
        rptTmptId: '',
        rptTmptName: '',
        rptTmptVersn: '',
        rptPeriod: ''
      }
    }
  },
  created () {
      
      
    this.init()
  },
  watch: {
      
      
    step: function (newValue, oldValue) {
      
      
      this.component = this.wizard[newValue].WKFL_STEP_APP
      if (newValue === this.wizard.length - 1) {
      
      
        this.nextText = '  完成  '
      } else {
      
      
        this.nextText = '下一步>'
      }
      if (newValue === 0) {
      
      
        this.lastBtnVisible = false
      } else {
      
      
        this.lastBtnVisible = true
      }
    }
  },
  methods: {
      
      
    async init () {
      
      
      let OPT_DEPT = {
      
      }
      await getDeptNoByEmpeNo().then((res) => {
      
      
        OPT_DEPT = res.OPT_DEPT
      })
      // 初始化字典
      this.dict.RATING_TYPE = await this.$getDictByCode('RATING_TYPE')
      this.dict.WKFL_STAGE = await this.$getDictByCode('WKFL_STAGE')
      this.dict.RATING_WKFL_TYPE = await this.$getDictByCode('RATING_WKFL_TYPE')
      const param0 = {
      
      
        RATING_ID: this.parentQuery.ratingId,
        ratingWkflType: this.parentQuery.ratingWkflType
      }
      await qryRatingResultList(param0).then((res) => {
      
      
        console.log(this.dict.RATING_WKFL_TYPE, this.parentQuery.ratingWkflType)
        res.ratingWkflTypeName = this.dict.RATING_WKFL_TYPE[this.parentQuery.ratingWkflType] ? this.dict.RATING_WKFL_TYPE[this.parentQuery.ratingWkflType].name : this.this.parentQuery.ratingWkflType
        res.RATING_TYPE_NAME = this.dict.RATING_TYPE[res.RATING_TYPE] ? this.dict.RATING_TYPE[res.RATING_TYPE].name : res.RATING_TYPE
        res.WKFL_STAGE_NAME = this.dict.WKFL_STAGE[res.WKFL_STAGE] ? this.dict.WKFL_STAGE[res.WKFL_STAGE].name : res.WKFL_STAGE
        this.ratingResult = res
        this.param = {
      
      
         
        }
        console.log('公共字段:', this.param)
      })

      // 2、查询对应向导流程数据:实现动态挂载组件,动态组件渲染,通过1定位到该用户执行到了哪个流程
      const param1 = {
      
      
        WKFL_STEP_TYPE: this.parentQuery.wkflStepType,
        RATING_ID: this.parentQuery.ratingId,
        RATING_WKFL_TYPE: this.parentQuery.ratingWkflType
      }
      await qryWkflWizardList(param1).then((res) => {
      
      
        for (const i in res.VALUE_LIST) {
      
      
          // 动态向vue挂载组件
          Vue.component(res.VALUE_LIST[i].WKFL_STEP_APP, () =>
            import('./components/' + res.VALUE_LIST[i].WKFL_STEP_APP)
          )
        }
        this.wizard = res.VALUE_LIST
        this.step = 0
        this.component = this.wizard[this.step].WKFL_STEP_APP // 默认渲染组件
      })
    },
    /**
    父组件点击下一步触发子组件方法,可直接在子组件定义名为 parentNextStepChange() 方法,该方法返回值必须为{status:true or false},来告诉父组件是否可以进行下一步操作,切记parentNextStepChange()方法内如果涉及到请求后端,一定要改成同步请求。
    如果子组件不需要控制下一步是否可以点击,则不需要定义parentNextStepChange方法;
    */
   async nextStep () {
      
      
      if (this.step <= this.wizard.length - 1) {
      
      
        let isContinue = true
       if (this.$refs.child.parentNextStepChange !== undefined) {
      
      
          const val = await this.$refs.child.parentNextStepChange()
           isContinue = val.status
       }
       if (isContinue && this.step !== this.wizard.length - 1) {
      
      
            this.step = this.step + 1
       }
       console.log('STEP+++++++' + this.step)
      }
    },
    lastStep () {
      
      
      if (this.step > 0) {
      
      
        this.step = this.step - 1
      }
    }
  }
}
</script>
<style scoped>
.body {
      
      
  padding: 16px 11px 11px 11px;
  background: #efefef;
  height: 100%;
}
.header {
      
      
  left: 12px;
  top: 16px;
  width: 100%;
  height: 48px;
  background-color: #ffffff;
  margin-bottom: 11px;
  padding: 13px 19px 13px 19px;
}
.header >>> span {
      
      
  font-family: MiSans-Medium;
  font-size: 14px;
  font-weight: 500;
  color: #202020;
}
.sider {
      
      
  left: 12px;
  top: 75px;
  width: 15%;
  height: 93%;
  background: #ffffff;
  float: left;
  margin-right: 11px;
  padding-left: 25px;
  padding-top: 37px;
  padding-right: 25px;
}
.content {
      
      
  left: 223px;
  top: 75px;
  width: 84%;
  height: 93%;
  background: #ffffff;
  float: left;
  padding: 10px 10px 10px 10px;
}
</style>

子组件

<template>
  <a-spin :spinning="loadding">
  </a-spin>
</template>
<script>
export default {
    
    
  props: {
    
    
    param: {
    
    
      type: Object,
      default: function () {
    
    
        return {
    
    
        }
      }
    }
  },
  data () {
    
    
    return {
    
    
      loadding: false,
    }
  },
  // created () {
    
    
  //   this.init()
  // },
  mounted () {
    
    

  },
  activated () {
    
    
    // keep-live 生命周期,每次进入即触发
    this.init()
  },
  methods: {
    
    
    async init () {
    
    
      await this.refreshFinData()
      await this.qryCustFinDataList()
    },
    /**
     * 监听父组件点击下一步,校验是否可以下一步操作
     * @return 必须返回 {
    
     status: true 向导进入下一步,flase 向导停留在当前 }
     */
    async parentNextStepChange () {
    
    
      const stepResult = await this.checkReportCount01()
      return stepResult
    },
    /**
     * 财报数量检查,判断查询结果大于等于3
     */
    async checkReportCount01 () {
    
    
      const stepResult = {
    
     status: false }
      const BEGINDATE = String(Number(String(this.param.rptPeriod).substring(0, 4)) - 2) + '1231'
      const checkParam = {
    
    
          CUST_ID: this.param.custId,
          BEGINDATE: BEGINDATE,
          ENDDATE: this.param.rptPeriod
      }
      await queryReportCount01(checkParam).then((res) => {
    
    
        if (res.RPT_CNT !== undefined) {
    
    
          if (res.RPT_CNT >= 3) {
    
    
            stepResult.status = true
          } else {
    
    
            this.$message.warning('')
          }
        } else {
    
    
          this.$message.error('服务器异常')
        }
      })
      return stepResult
    }

  }
}
</script>
<style scoped>

</style>


扩展: 如果需要在每次上下一步来回切换组件时都要触发的方法,则需要将该方法放在keep-live的生命周期内,而非created

 activated () {
    
    
    // keep-live 生命周期,每次进入即触发
    this.init()
  },

猜你喜欢

转载自blog.csdn.net/weixin_43865196/article/details/125726546