关于element中el-option绑定数据,数据更新未重新渲染

        这几天开发vue3项目,引用elment中的el-select和el-option进行下拉框的渲染。在此过程中出现了这样的问题(下述代码有所简化):

首先,我通过下述代码对el-option进行数据绑定

<div class="myInfo_type">
	<span
	  @click="handleClick"
	>
	</span>
</div>
<div class="myInfo_date">
	<el-select
	  v-model="month_selected"
	  placeholder="筛选时间"
	>
	  <el-option
		v-for="item in month_selector"
		:key="item.value"
		:label="item.title"
		:value="item.value"
	  >
	  </el-option>
	</el-select>
</div>

其次,在setup中对变量 month_selector进行定义,设置初始值并注入至data

setup() {
	let month_selected = ref('');
	let month_selector = [
		{
			title: '筛选时间',
			value: '0',
		}
	];

	return {
	  month_selector,
	  month_selected
	};
}

最后,定义handleClick方法更新month_selector的值,以达到动态更新下拉框内容的目的。

methods: {
   handleClick(index) {
	  this.month_selector = [
		  {title: "筛选时间", value: "0"},
		  {title: "2021年6月", value: "2021年6月"}
	  ];
	} 
}

        但是发现,点击触发handleClick方法后,下拉框内容并未发生改变。但是用原生的select和option却能动态更新。那么el-option数据不更新的原因是什么呢?于是我找到elment中el-option的源码:

<template>
  <li
    @mouseenter="hoverItem"
    @click.stop="selectOptionClick"
    class="el-select-dropdown__item"
    v-show="visible"
    :class="{
      'selected': itemSelected,
      'is-disabled': disabled || groupDisabled || limitReached,
      'hover': hover
    }">
    <slot>
      <span>{{ currentLabel }}</span>
    </slot>
  </li>
</template>

<script type="text/babel">
  import Emitter from 'element-ui/src/mixins/emitter';
  import { getValueByPath, escapeRegexpString } from 'element-ui/src/utils/util';
  export default {
    mixins: [Emitter],
    name: 'ElOption',
    componentName: 'ElOption',
    inject: ['select'],
    props: {
      value: {
        required: true
      },
      label: [String, Number],
      created: Boolean,
      disabled: {
        type: Boolean,
        default: false
      }
    },
    data() {
      return {
        index: -1,
        groupDisabled: false,
        visible: true,
        hitState: false,
        hover: false
      };
    },
    computed: {
      isObject() {
        return Object.prototype.toString.call(this.value).toLowerCase() === '[object object]';
      },
      currentLabel() {
        return this.label || (this.isObject ? '' : this.value);
      },
      currentValue() {
        return this.value || this.label || '';
      },
      itemSelected() {
        if (!this.select.multiple) {
          return this.isEqual(this.value, this.select.value);
        } else {
          return this.contains(this.select.value, this.value);
        }
      },
      limitReached() {
        if (this.select.multiple) {
          return !this.itemSelected &&
            (this.select.value || []).length >= this.select.multipleLimit &&
            this.select.multipleLimit > 0;
        } else {
          return false;
        }
      }
    },
    watch: {
      currentLabel() {
        if (!this.created && !this.select.remote) this.dispatch('ElSelect', 'setSelected');
      },
      value(val, oldVal) {
        const { remote, valueKey } = this.select;
        if (!this.created && !remote) {
          if (valueKey && typeof val === 'object' && typeof oldVal === 'object' && val[valueKey] === oldVal[valueKey]) {
            return;
          }
          this.dispatch('ElSelect', 'setSelected');
        }
      }
    },
    methods: {
      isEqual(a, b) {
        if (!this.isObject) {
          return a === b;
        } else {
          const valueKey = this.select.valueKey;
          return getValueByPath(a, valueKey) === getValueByPath(b, valueKey);
        }
      },
      contains(arr = [], target) {
        if (!this.isObject) {
          return arr && arr.indexOf(target) > -1;
        } else {
          const valueKey = this.select.valueKey;
          return arr && arr.some(item => {
            return getValueByPath(item, valueKey) === getValueByPath(target, valueKey);
          });
        }
      },
      handleGroupDisabled(val) {
        this.groupDisabled = val;
      },
      hoverItem() {
        if (!this.disabled && !this.groupDisabled) {
          this.select.hoverIndex = this.select.options.indexOf(this);
        }
      },
      selectOptionClick() {
        if (this.disabled !== true && this.groupDisabled !== true) {
          this.dispatch('ElSelect', 'handleOptionClick', [this, true]);
        }
      },
      queryChange(query) {
        this.visible = new RegExp(escapeRegexpString(query), 'i').test(this.currentLabel) || this.created;
        if (!this.visible) {
          this.select.filteredOptionsCount--;
        }
      }
    },
    created() {
      this.select.options.push(this);
      this.select.cachedOptions.push(this);
      this.select.optionsCount++;
      this.select.filteredOptionsCount++;
      this.$on('queryChange', this.queryChange);
      this.$on('handleGroupDisabled', this.handleGroupDisabled);
    },
    beforeDestroy() {
      const { selected, multiple } = this.select;
      let selectedOptions = multiple ? selected : [selected];
      let index = this.select.cachedOptions.indexOf(this);
      let selectedIndex = selectedOptions.indexOf(this);
      // if option is not selected, remove it from cache
      if (index > -1 && selectedIndex < 0) {
        this.select.cachedOptions.splice(index, 1);
      }
      this.select.onOptionDestroy(this.select.options.indexOf(this));
    }
  };
</script>

我们可以看出来,el-option中展示的内容其实是计算属性currentLabel,而currentLabel是通过监听组件的label和value属性,而label和value绑定的分别是month_selector每项的title和value字段。

        那么我推测,虽然month_selector发生改变,但因为其没有响应式的特性,所以并不会引发label和value的监听。因此,我通过ref关键字将month_selector定义为响应式变量,测试通过。 

let month_selector = ref([
		{
			title: '筛选时间',
			value: '0',
		}
	]);

        也许会有人问,对象变量不应该是用reactive赋予响应式特性吗?这就需要清楚ref和reactive的区别:

        reactive虽然是将对象赋予响应式特性,但由于我的handleClick方法中是直接给month_selector赋值,这样就会丢失响应式的特性。因此大部分情况下还是建议用ref附加响应式特性,reactive操作不当容易丢失响应式特性。

        ref是将原始数据类型(字符串、数字等等)赋予响应式特性,但是查看ref的源码(如下),由此可见ref也可以为对象赋予响应式特性。

         当然,以上问题除了增加响应式特性之外,也可以通过其他方式解决,比如:

        (方法一)给el-option的父级元素(即el-select),定义key属性。当el-option所绑定的数据发生变化的同时,改变父级元素的key属性,这样就会重新渲染父级元素,同时就会重新渲染el-option;

        (方法二)将el-option的for循环再封装为新的组件,这样绑定数据发生变化,就会重新渲染该组件。

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
根据你提供的引用内容,el-option数据刷新的问题可能是由于焊缝表格的下拉框的options数据更新了,但是焊缝tab页没有重新渲染导致的。因此,为了解决el-option数据刷新的问题,你可以尝试重新渲染焊缝tab页,以使下拉框的数据更新。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [关于elementel-option绑定数据数据更新重新渲染](https://blog.csdn.net/u012690202/article/details/119298222)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [VUE table表格动态添加一列数据,新增的这些数据不可以编辑(v-model绑定数据不能实时更新)](https://download.csdn.net/download/weixin_38626192/13132028)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [el-option的值设置了,但视图没更新。](https://blog.csdn.net/qq_23207707/article/details/123363012)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值