当前位置: 首页 > news >正文

日常开发记录-radioGroup组件

日常开发记录-radioGroup组件

  • 1.前提
  • 2.问题:无限循环调用
  • 3.解释
  • Vue 事件传播机制分析与无限循环原因解释
  • 4.解决

1.前提

在上一章的,我们实现了radio组件。从这进入了解
新增个radioGroup组件呢。

<template>
  <div
    class="q-radio-group"
    role="radiogroup"
  >
    <slot></slot>
  </div>
</template>

<script>
  export default {
    name: 'MyRadioGroup',
    componentName: 'MyRadioGroup',
    props: {
      value: {},
      disabled: Boolean,
      name: String
    },
    created() {
      this.$on('change', value => {
        this.$emit('change', value);
      });
    },
    watch: {
      value(value) {
        // 当值变化时,通知子组件
        this.$nextTick(() => {
          // this.$children.forEach(child => {
          //   if (child.$options.name === 'MyRadio') {
          //     child.$refs.radio.checked = child.label === value;
          //   }
          // });
        });
      }
    }
  };
</script>

<style>
.q-radio-group {
  display: inline-block;
}
</style>


原来的radio组件改写成

<template>
  <label
    class="q-radio"
    :class="{
      'is-disabled': isDisabled,
      'is-checked': model === label
    }"
  >
    <span class="q-radio__input"
      :class="{
        'is-disabled': isDisabled,
        'is-checked': model === label
      }"
    >
      <span class="q-radio__inner"></span>
      <input
        ref="radio"
        type="radio"
        class="q-radio__original"
        :value="label"
        :name="name"
        :disabled="isDisabled"
        v-model="model"
        @change="handleChange"
      />
    </span>
    <span class="q-radio__label">
      <slot></slot>
      <template v-if="!$slots.default">{{label}}</template>
    </span>
  </label>
</template>

<script>
  export default {
    name: 'MyRadio',
    props: {
      value: {},
      name: String,
      label: {},
      disabled: Boolean,
    },
    data() {
      return {
        // 预先定义 _radioGroup,提高代码可读性
        _radioGroup: null
      };
    },
    computed: {
      isGroup() {
        let parent = this.$parent;
        while (parent) {
          if (parent.$options.name !== 'MyRadioGroup') {
            parent = parent.$parent;
          } else {
            this._radioGroup = parent;
            return true;
          }
        }
        return false;
      },
      model: {
        get() {
          return this.isGroup ? this._radioGroup.value : this.value;
        },
        set(val) {
          if (this.isGroup) {
            // 使用 $emit 向上传递事件
            this._radioGroup.$emit('input', val);
          } else {
            this.$emit('input', val);
          }
        }
      },
      isDisabled() {
        // 考虑组的禁用状态
        return this.isGroup 
          ? this._radioGroup.disabled || this.disabled 
          : this.disabled;
      }
    },
    methods: {
      handleChange() {
        // 使用 $nextTick 确保状态已更新
        this.$nextTick(() => {
          // 触发 change 事件
          this.$emit('change', this.model);
          // 如果在组中,也通知组
          if (this.isGroup) {
            this._radioGroup.$emit('change', this.model);
          }
        });
      }
    }
  }
</script>

引用:

<template>
  <div id="app">
    <el-container>
      <el-header>
        <h1>Vue 2 + Element UI Template</h1>
      </el-header>
      <el-main>
        <el-row>
          <el-col :span="12" :offset="6">
            <el-card>
              <div slot="header">
                <span>欢迎使用</span>
              </div>
              <el-button type="primary">点击我</el-button>
            </el-card>
          </el-col>
        </el-row>
      </el-main>
      <input type="radio" id="contactChoice1" name="contact" value="email" />
      <label for="contactChoice1">电子邮件</label>
      <input type="radio" id="contactChoice2" name="contact" value="phone" />
      <label for="contactChoice2">电话</label>
      <input type="radio" id="contactChoice3" name="contact2" value="mail" />
      <label for="contactChoice3">邮件</label>

      <MyRadio v-model="currentValue.aaa" name="aaa" @input="handleInput" @change="handleChange" label="男"></MyRadio>
      <MyRadio v-model="currentValue.aaa" name="aaa" @input="handleInput" @change="handleChange" label="女"></MyRadio>
      <MyRadio v-model="currentValue2" name="bbb" @input="handleInput" @change="handleChange" label="未知">未知</MyRadio>
      <MyRadioGroup v-model="currentValue.bbb" name="bbb" @change="handleGroupChange">
        <MyRadio label="男"></MyRadio>
        <MyRadio label="女"></MyRadio>
      </MyRadioGroup>
      <el-button @click="changeGroupVal">改变group的绑定值</el-button>
      <el-radio v-model="radio" label="1" @input="change">备选项</el-radio>
      <el-radio v-model="radio" label="2">备选项</el-radio>
    </el-container>
  </div>
</template>

<script>
import MyRadio from './components/myRadio.vue'
import MyRadioGroup from './components/myRadioGroup.vue'
export default {
  name: 'App'
  , data () {
    return {
      currentValue: {
        aaa: '男',
        bbb: ''
      },
      currentValue2: '',
      radio: '1'
    }
  },
  components: {
    MyRadio,
    MyRadioGroup
  },
  methods: {
    handleInput (event) {
      console.log('input event', event)
    },
    changeGroupVal () {
      this.currentValue.bbb = '女'
    },
    handleChange (val) {
      console.log('change event', val)
    },
    change (val) {
      console.log(val)
    },
    handleGroupChange (val) {
      console.log('group', val)
    }
  }
}
</script>

主要在于radio的isGroup和原绑定值的改变,radiogroup就是个插槽。

2.问题:无限循环调用

在这里插入图片描述
会出现无限调用radiogroup组件emit出来的change事件。为什么呢?感觉没问题的应该。
原有的逻辑,事件传递链分析:
当您点击 RadioGroup 中的一个选项时,事件流程如下:
MyRadio 的 model setter 被触发,它调用 this._radioGroup. e m i t ( ′ i n p u t ′ , v a l ) 同时, M y R a d i o 的 h a n d l e C h a n g e 方法被触发,它调用 t h i s . emit('input', val) 同时,MyRadio 的 handleChange 方法被触发,它调用 this. emit(input,val)同时,MyRadiohandleChange方法被触发,它调用this.emit(‘change’, this.model) 和 this._radioGroup. e m i t ( ′ c h a n g e ′ , t h i s . m o d e l ) M y R a d i o G r o u p 监听 到 ′ c h a n g e ′ 事件,它又调用 t h i s . emit('change', this.model) MyRadioGroup 监听到 'change' 事件,它又调用 this. emit(change,this.model)MyRadioGroup监听change事件,它又调用this.emit(‘change’, value)。
感觉这样就完了呀。怎么会一直重复的调用change事件呢。
??????

3.解释

Vue 事件传播机制分析与无限循环原因解释

分析为什么修改事件名可以解决无限循环问题,并解释 Vue 中 $emit 和 $on 的工作原理。
问题根源: 组件自我监听
查看自己的 MyRadioGroup 组件代码:
这里发现了关键问题 - 组件正在监听自己发出的事件,并且在监听器中又发出同名事件,创建了一个经典的无限循环:
步骤1.MyRadio 组件触发 change 事件,并将值发送给 MyRadioGroup
步骤2.MyRadioGroup 接收 change 事件,通过 o n 监听器处理它步骤 3. 处理器调用 t h i s . on 监听器处理它 步骤3.处理器调用 this. on监听器处理它步骤3.处理器调用this.emit(‘change’, value),再次向自己发送 change 事件
步骤4.这又激活了同一个监听器,返回步骤 3,形成无限循环
Vue 事件机制解析
基本工作流程:
$on 将事件处理器存储在组件实例的 _events 对象中
$emit 查找并调用存储在 _events[eventName] 中的处理器
关键点: 当组件对自己发出的事件设置监听器时,每次调用 $emit 都会触发这些监听器,包括那些由同一组件设置的监听器。

4.解决

所以我们只要抛出的方法名变一下就行

this._radioGroup.$emit('handleChange', this.model);

//接受
   created() {
      this.$on('handleChange', value => {
        this.$emit('change', value);
      });
    }

相关文章:

  • 【并发编程】JUC常用类以及线程池
  • 在Simulink中将Excel数据导入可变负载模块的方法介绍
  • Docker Swarm 集群操作实践
  • django框架 [面试篇]
  • python-leetcode-最大连续1的个数 III
  • 【leetcode hot 100 146】LRU缓存
  • 如何修复 Tauri 发布后程序运行时显示 `asset not found: index.html` 的问题
  • 父组件中循环生成多个子组件时,有且只有最后一个子组件的watch对象生效问题及解决办法
  • NFS writeback流程中的GFP_NOFS
  • Docker安装部署RabbitMQ
  • 条款1:理解模版性别推导
  • C#带多组标签的Snowflake SQL查询批量数据导出程序
  • linux 命令 grep
  • Embedding模型到底是什么?
  • C++11 编译使用 aws-cpp-sdk
  • 专题地图的立体表达-基于QGIS和PPT的“千层饼”视图制作实践
  • 后端主流数据库分析
  • 前端面试:React生态有哪些?
  • 【从零开始学习计算机科学】数据库系统(八)数据库的备份和恢复
  • 神经网络常用库-torch(基础操作张量)
  • 龙华新区网站制作/拍照搜索百度识图
  • 做偏门网站/关键词seo价格
  • 宝安led行业网站建设/如何给网站做推广
  • 大足网站建设/泉州网站关键词排名
  • 潍坊企业自助建站/百度关键词搜索次数
  • 嵊州门户网站/杭州网站排名提升