VUE中多级透传的常用优化方法

VUE中多级透传的常用方法

多级传递参数,自定义函数

  1. 根组件 parent.vue
  <template>
    <div class="w-100p h-100p relative">
    <my-console-assign
    task-type="5"
    :card-height="cardHeight"
    :subtract-width="subtractWidth"
    is-enhance-find-lesson
    :is-show-none="true"
    :is-dispatch="false"
    @handleButtonEvent="handleButtonEvent"
    ></my-console-assign>
    </div>
    </template>
    <script>
    import myConsoleAssign from '@/pc/view/listenAndDiscuss/myConsole/myConsoleAssign';
    import WrapperContentBox from '@/pc/components/wrapperContentBox/wrapperContentBox.vue';
    export default {
        name: 'parent',
        components: {
            myConsoleAssign
        },
        props: {
            // 面板高度
            cardHeight: {
                default: 222,
                type: Number
            },
            // 左侧距离
            subtractWidth: {
                default: 0, //330通用	(减去了左侧的区块)			0(屏幕百分比宽度)
                type: Number
            }
        },
        data() {
            return {};
        },
      methods:{
        handleButtonEvent(){
            
        }
      }
    };
    </script>
    <style lang="scss" scoped></style>

  1. 中间组件

props(父组件向子组件传值) 子传父应该用通过绑定事件然后及$emit传值,普通组件间传值用全局事件总线 $bus

中间组件不用接收 props 可以使用

v-bind=“$attrs” 传递 下级组件调用即可

自定义事件 v-on=“$listeners”

.sync 子更新父数据(当一个子组件改变了一个 prop 的值时,这个变化也会同步到父组件中所绑定。 .sync 它会被扩展为一个自动更新父组件属性的 v-on 监听器)

:data.sync=“dataList”

:columns=“getTableColumns()”

:current-page.sync=“page”

<template>
	<div class="border-box flex-column p-20 h-100p w-100p">
		<el-select class="m-b-20 select-drop-list select-w-custom" v-model="currentTermId" :placeholder="formatTerm">
			<el-option
				v-for="item in schoolTermList"
				:key="item.school_term_id"
				:label="item.label"
				:value="item.val"
			>
			</el-option>
		</el-select>
      <module-wrap-title
          title="我的听课记录"
          title-class="f-s-18"
          :margin-bottom="20"
          :height="20"
          is-show-notice-board
          more-class="f-s-14  col-b-blue bold" 
      >
      </module-wrap-title>
      <wrapper-content-box
          :data-list="dataListLessRecordList"
          @diffSize="diffSize"
          @handleButtonEvent="handleButtonEvent"
          v-on="$listeners"
          v-bind="$attrs"
          :line-number="1"
      ></wrapper-content-box>
	</div>
</template>
<script>
import { getCurrentMonthRangeDate } from '@/utils/old/time'; 
import myConsole from '@/pc/view/listenAndDiscuss/myConsole/mixins/myConsole'; 

export default {
	components: {
		ModuleWrapTitle,
		WrapperContentBox, 
	},
	filters: { 
	},
	mixins: [myConsole],
	props: { 
		taskType: {
			type: String,
			default: ''
		}
	},
	data() {
		return {
			cardWidth: '325px',
			dataList: [], 
			dateParams: {}, 
		};
	},
	computed: {   
	},
	watch: { 
		currentTerm(newVal) {
			if (newVal.term_start) {
				//newVal?.term_year + '' + (newVal?.term_number === '1' ? '春季' : '秋季') + '学期';
				this.currentTerm.term_start = newVal.term_start;
				this.currentTerm.term_end = newVal.term_end;
				// this.getStatisticData();
			}
		}, 
	},
	mounted() {},
	created() {
		// 查询的用户id
		this.queryUserId = this.$route.query.id ? this.$route.query.id : this.userInfo.user_id;
		  
	},
	methods: {
		init() { 
		}, 
		// 格式化当前日期选项f
		formatTermLabel(percentage) {
			return percentage === 0 ? '---' : `${percentage}%`;
		},    
	}
};
</script>

<style lang="scss" scoped>
$borderColor: #e6e6e6; 

::v-deep .el-progress {
	.el-progress-bar__outer,
	.el-progress-bar__inner {
		border-radius: 4px;
	}
}

@media screen and (max-width: 1919px) {
	.calendar-min {
		width: 304px;
	}
}

@media screen and (min-width: 1920px) {
	.calendar-min {
		width: 332px;
	}
} 
</style>

  1. 孙子组件
<template>
  <div class="flex flex-wrap wrapper-box">
    <!--放置占位卡片-->
    <MediaWrapper v-if="isSeat" :match-size="matchSizeInfo.width">
      <slot></slot>
    </MediaWrapper>
    <!--添加-->
    <MediaWrapper v-if="isAdd" :card-width="cardWidth" :match-size="matchSizeInfo.width">
      <div class="w-100p flex-center pointer border-box p-20 brs8 white-bg" :style="{ height: `${addHeight}px` }">
        <div class="justify-center align-center flex-col add w-100p h-100p" @click="add">
          <img src="@static/img/add_supervisor.png" alt="" class="w-32 h-32" />
          <div class="m-t-16">{{ addTitle }}</div>
        </div>
      </div>
    </MediaWrapper>
    <MediaWrapper
        v-for="(item, index) in newList"
        :key="index"
        is-margin
        :card-width="cardWidth"
        :match-size="matchSizeInfo.width"
    > <!--新版听评课卡片-->
      <enhance-find-lesson
          v-if="isEnhanceFindLesson"
          :item-info="item"
          v-bind="$attrs"
          v-on="$listeners"
      ></enhance-find-lesson>
      <!--督导评课基本设置-->
      <listen-manage-card
          :item-info="item"
          v-if="isListenManage"
          :threshold-value="thresholdValue"
          v-bind="$attrs"
      ></listen-manage-card>
    </MediaWrapper>
    <div
        v-if="newList.length === 0 && isShowNone"
        class="flex-1 m-10 "
        v-bind="$attrs"
        :title="noDataTitle"
        v-empty
    ></div>
  </div>
</template>
<script> 
export default {
  name: 'wrapperContentBox',
  components: { 
  },
  mixins: [multiPlatformType],
  props: {
    dataList: {
      default: () => {
        return [];
      },
      type: Array
    },
    //卡片前需要占位的个数
    hasSizeNumber: {
      default: 0,
      type: Number
    },
    //是否单行展示
    isWrap: {
      default: false,
      type: Boolean
    },
    //是否有添加的卡片
    isAdd: {
      default: false,
      type: Boolean
    }, 
    //新开页面
    isOpen: {
      default: false,
      type: Boolean
    }, 
    // 是否阈值
    thresholdValue: {
      default: false,
      type: Boolean
    }, 
  },
  data() {
    return {
      isScrollbarY: false,
      diffSize: 0, 
      // 当前可用的宽度
      freeScreenWidth: 0,
      // 当前的matchSize信息
      matchSizeInfo: {}
    };
  },
  computed: { 
  },
  created() { 
  },

  // 大量页面用该组件包裹,所以缓存后的触发调用接口也放在该组件内
  activated() {
    // 防止多掉一次接口:created或者mounted中也会getData
    if (this.$route.meta?.isFirstEnter === false) {
      this.calcPageSize();
    }
  },

  methods: {
    async calcPageSize() {
      await this.$store.dispatch('app/getViewWidth');
      // 当前屏幕可用宽度
      this.freeScreenWidth = this.$store.state.app.viewWidth - this.subtractWidth;
      console.log('freeWidth', this.freeScreenWidth);
      this.matchSizeInfo = getMatchSizeInfo(this.freeScreenWidth, this.pageSizeInDiffPx);
      this.diffSize = listPageSize(this.freeScreenWidth, this.lineNumber);
      if (this.isAdd) {
        this.diffSize = this.diffSize - 1;
      }
      this.$emit('diffSize', this.diffSize);
    }, 
    toDetail(name, id, type, isPassword, isNewOpen, val) {
      let routeUrl = this.$router.resolve({
        name: name
      }); 
      if (isNewOpen) {
        const token = getStorage(AccessToken);
        window.open(
            window.location.origin + window.location.pathname + routeUrl.href + '?id=' + id + '&token=' + token
        );
      } else {
        if (isPassword) {
          passwordDia(this, id, name, type, this.isOpen);

          return;
        } else if (this.isOpen) {
          const token = getStorage(AccessToken);
          window.open(
              window.location.origin +
              window.location.pathname +
              routeUrl.href +
              '?id=' +
              id +
              '&token=' +
              token
          );
          return;
        }
        this.$router.push({
          name: name,
          query: { 
            ...concatDistrictParams(this.$isDistrict, { id: id }, { isDistrict: 1 })
          }
        });
      }
    }
  }
};
</script>
<style lang="scss" scoped> 
</style>


$emit(子传父) 使用 .sync省略手动监听

<!--- 父组件 --->
<template>
    <div class="app">
        <Student v-on:at="getStudentName" v-on:go="getStudentAge"></Student>
    </div>
</template>

<script>
    // 引入Student组件
    import Student from './components/Student.vue' 
    // 定义vue组件
    export default {
        name:'App',
        components:{
            Student
        },
        data() {
            return {
                msg:'你好啊'
            }
        },
        methods: {
            getStudentName(name) {
                console.log('app收到了学生名',name);
            },
            getStudentAge(age) {
                console.log('app收到了学生年龄',age);
            }
        }
    }
</script> 


		<!--- 子组件 --->
		<template>
		    <div class="student">
		        <h2>学生姓名:{{name}}</h2>
		        <h2>学校年龄:{{age}}</h2>
		        <button @click="sendStudentName">把学生名给app</button>
		        <button @click="sendStudentAge">把学生年龄给app</button>
		    </div>
		</template>

<script>
    export default {
        name:'MyStudent',
        data() {
            return {
               name:'张三',
               age:18
            }
        },
        methods: {
            sendStudentName() {
                // 触发Student组件实例对象vc上的at事件(绑定at事件)
                this.$emit('at',this.name)
            },
            sendStudentAge() {
				 // 触发Student组件实例对象vc上的go事件(绑定go事件)
                this.$emit('go',this.age)
			}
    }
</script> 
  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值