为什么vue2+antdv render()创建下拉框滚动事件绑定不生效?

项目中有许多form表单提交,前辈就封装了一个组件
使用动态render()函数创建表单,对antdv 组件进行二次封装
上代码
----------------------------------正常界面,

<template>
  <page-header-wrapper :title="false">
    <div class="add-frame-list" style="height: 100%;">
      <div class="add-frame">
        <span class="title">{{ supplier_id? $t("edit")+$t('supplier') : $t("plus")+$t('supplier') }}</span>
      </div>
      <div class="content">
        <form-container
          v-if="Object.values(dictObj).length > 0"
          :formParams="productInfo"
          :dictObj="dictObj"
          ref="formContainer"
        ></form-container>
        <div class="action-button">
          <a-button type="primary" @click="saveData">{{ $t('save') }}</a-button>
        </div>
      </div>
    </div>
  </page-header-wrapper>
</template>
<script>
import FormContainer from "@/views/common/components/FormContainer.vue";
import { dictAPI } from "@/utils/dict.js";
import industrialEnt from "@/mixin/industrialEnt.js";
export default {
  mixins: [industrialEnt],
  components: {
    FormContainer
  },
  data() {
    let that = this;
    return {
      productInfo: {
        industry_id: {
          category: "customer-select",
          value: undefined,
          title: "产业",
          require: true,
          isUserDefind: true,
          teledata: true,
          params: {
            options: []
          },
          events: {
            change(value) {
              that.changeIndustry(value,'这里正常触发,change事件');
            },
            popupScroll(value) {
              console.log(value,'问题就在这,这里是不会触发的,我要在这里使用滚动事件,下拉框数据很多,足够触发这滚动事件');
            },
          }
        },
        ent_id: {
          category: "customer-select",
          value: undefined,
          title: "企业",
          require: true,
          isUserDefind: true,
          teledata: true,
          params: {
            options: []
          },
          events: {
            change(value) {
              // console.log(value, "***************");
            }
          }
        }
      },
      dictObjCopy: {},
      supplier_id: ""
    };
  },
  computed: {
    dictObj() {
      if (this.industryList.length > 0 && this.industryEntList.length > 0) {
        return {
          ...this.dictObjCopy,
          industry_id: this.dealDict(this.industryList, [
            "industry_id",
            "industry_name",
            "org_id"
          ]),
          ent_id: this.dealDict(this.industryEntList, [
            "ent_id",
            "ent_name",
            "model_class_id"
          ])
        };
      } else {
        return {};
      }
    }
  },
  created() {
    this.getDict();
  },
  methods: {
    dealDict(arr, list) {
      return arr.map(item => {
        return {
          dic_key: item[list[0]],
          dic_v1: item[list[1]],
          dic_type_id: item[list[2]]
        };
      });
    },
    async getDict() {
      let res = await dictAPI(["project_type_id"]);
      this.dictObjCopy = res;
    },
  }
};
</script>

--------------------------- FormContainer 表单 组件

<template>
  <a-form-model
    :class="coverDefineClass"
    ref="formContainer"
    :layout="layout"
    :model="formParams"
    :hideRequiredMark="true"
  >
    <a-form-model-item
      v-for="(node, name) in formParams"
      :key="name"
      :prop="`${name}.value`"
      v-show="!node.isHiddenCurItem"
      :rules="addRules(node)"
      :class="{ 'holder-one-row': node.holderOneRow }"
    >
      <label v-if="(node.title ?node.title: '') !== ''" :title="node.title" slot="label">
        {{ node.title }}
        <span v-if="node.unit">({{ node.unit }})</span>
        <span class="user-defind-required" v-if="node.require">*</span>
      </label>
      <FormsDistribution
        v-bind="node"
        v-model="node.value"
        :class="{ 'is-view-state': isViewModel }"
      ></FormsDistribution>
    </a-form-model-item>
  </a-form-model>
</template>

<script>
import FormsDistribution from "./FormsDistribution.vue";
import getTeledata from "@/utils/getTeledata";
import { dealDict } from "@/utils/dict.js";
let computedValueFn = null;
export default {
  name: "FormContainer",
  components: {
    FormsDistribution
  },
  watch: {
    formParams: {
      deep: true,
      handler(val) {
        if (!this.needComputedValue || !computedValueFn) return;
        // 当需要有计算值时 计算当前功能
        computedValueFn.bind(val)();
      }
    },
    isViewModel() {
      this.setViewModel();
    }
  },
  props: {
    // 序列化参数
    formParams: {
      type: Object,
      default() {
        return {};
      },
      required: true
    },
    dictObj: {
      type: Object
    },
    // 排列方式,同Ant form 表单
    layout: {
      type: String,
      default: "vertical"
    },
    // 需要计算值
    needComputedValue: {
      type: Boolean,
      default: false
    },
    // 覆盖当前默认样式
    coverDefineClass: {
      type: String,
      default: "user-defind-form"
    },
    // 切换至查看转态
    isViewModel: {
      type: Boolean,
      default: false
    }
  },
  watch: {
    dictObj: {
      deep: true,
      handler(val, oldVal) {
        this.dealObject();
      }
    }
  },
  created() {},
  mounted() {
    this.dealObject();
  },
  methods: {
    dealObject() {
      // 当需要远程数据填充表单数据
      // 则执行相关操作
      Object.keys(this.formParams).forEach(name => {
        const item = this.formParams[name];
        if (item.teledata) {
          item.params.options = dealDict(this.dictObj[name]);
        }
        // 计算出当前是否有计算函数
        if (item.computedValue) {
          computedValueFn = item.computedValue;
        }
        // 如果当前为查看转态,则将每个表单置为disabled
        if (this.isViewModel) {
          this.setViewModel();
        }
      });
    },
    // 设置当前为查看状态,当为查看状态是,所有输入表单为不显示
    setViewModel() {
      Object.keys(this.formParams).forEach(name => {
        const item = this.formParams[name];
        if (!item.params) {
          item.params = {};
        }
        item.params.disabled = this.isViewModel;
      });
    },
    addRules(node) {
      const temp = [];
      if (node.require) {
        temp.push({
          required: true,
          message: `${node.title}不能为空!`,
          trigger: ["change", "blur"]
        });
      }
      // 另外添加的规则
      if (node.extendRule) {
        temp.push(...node.extendRule);
      }
      return temp;
    },
    // 清空或填入当前表单内的数据
    handleCurInputValue(rowData) {
      return {
        setData: () => {
          Object.keys(this.formParams).forEach(name => {
            this.formParams[name].value = rowData[name];
          });
        },
        clearAllData: () => {
          Object.keys(this.formParams).forEach(name => {
            this.formParams[name].value = "";
          });
        }
      };
    },
    // 输出当前键值对以及extraParams中额外参数数据JSON数据需要的字段
    outputSaveFormater() {
      let temp = {};
      Object.keys(this.formParams).forEach(name => {
        const node = this.formParams[name];
        temp[name] = node.value;
        // 如果有额外参数,直接转入传参结构数据中
        if (node.extraParams) {
          temp = { ...temp, ...node.extraParams };
        }
      });
      return temp;
    },
    // 校验所有需要检验的数据
    validAllData() {
      return new Promise((resolve, reject) => {
        this.$refs.formContainer.validate(valid => {
          if (valid) {
            const data = this.outputSaveFormater();
            resolve(data);
          } else {
            reject(false);
          }
        });
      });
    },
    // 清空所有表单内的数据
    resetFormValue() {
      this.$refs.formContainer.resetFields();
    },
    // 校验单列表单
    triggerOneColumn(name) {
      this.$refs.formContainer.validateField(`${name}.value`);
    }
  }
};
</script>

<style lang="less" scoped>
.user-defind-required {
  color: #f5222d;
  font-family: SimSun, sans-serif;
}
// 查看转态下的样式
.is-view-state {
  background-color: #fafafa;
  color: rgba(0, 0, 0, 0.85);
  border: 0;
  cursor: text;
  /deep/ .ant-input.ant-input-disabled {
    border: 0;
    color: rgba(0, 0, 0, 0.85);
    cursor: text;
  }
  /deep/ .ant-cascader-picker-arrow {
    display: none;
  }
  /deep/ .ant-calendar-range-picker-input {
    cursor: text;
  }
}
</style>

------------------------- FormsDistribution 这个是创建组件rander函数

<!-- 根据传入表单类型,派发一个ant表单 -->
<script>
// import Vue from "vue";
export default {
  name: "functionalComponents",
  functional: true,
  props: {
    value: undefined,
    category: {
      type: String,
      default: "",
      required: true
    },
    params: {
      type: Object,
      default() {
        return {};
      }
    },
    events: {
      type: Object,
      default: () => {}
    }
  },
  // a-input组件,需明确指明functional的绑定事件为 change.value
  model: {
    prop: "value",
    // 这里好像不影响,无论怎么写好像都不对
    // event: "change.value", // 最原始只有这行代码
    // events: ["change","popupScroll"]  // 这行代码为了测试添加的,不生效
  },
  render(h, context) {
    const { props, data, children, scopedSlots,listeners } = context;
    console.log(props.events, data.on,'props.events 是可以输出我绑定的popupScroll 函数,但是不执行**********');
    let tempParams = props.params;
    // 添加上自定义事件
    data.on = { ...data.on, ...props.events };
    // console.log(data.on,'最终data。on 也是有我绑定的 popupScroll 函数了,是不执行的 **********');
    // 如果为自定义组件,遵从预定数据格式传参,则转换prop参数类型
    if ((tempParams.placeholder ?? "") === "") {
      const labelTxt = props.category.match(/(select|cascader)/g)
        ? "选择"
        : "输入";
      tempParams.placeholder = `请${labelTxt}${data.attrs.title}`;
    }
    if (data.attrs.isUserDefind) {
      tempParams = { params: tempParams };
    }
    return h(
      props.category,
      {
        ...data,
        props: tempParams,
        listeners,
        scopedSlots
      },
      children
    );
  }
};
</script>

各位大佬们求指教 为什么我创建出来的下拉框,无法正确执行滚动事件,而同样创建出来的change就能触发
因为代码是前辈写的,而且找不到人,我自己对rander()也不熟悉,求指教,已经一天了,如果在无法解决,我就得 在 FormContainer 表单 组件 中手动写各种输入框了
求大佬指教

表单赋值方式
setTimeout(() => {

this.$refs.formContainer.handleCurInputValue(object).setData();

}, 100);

阅读 2.4k
1 个回答
<template>
  <a-select v-model="selectedValue" @dropdownVisibleChange="handleDropdownVisibleChange">
    <template #dropdownRender="{ menu }">
      <div @scroll="handleScroll">
        {{ menu }}
      </div>
    </template>
    <a-select-option value="option1">Option 1</a-select-option>
    <a-select-option value="option2">Option 2</a-select-option>
   
  </a-select>
</template>

<script>
export default {
  data() {
    return {
      selectedValue: null
    };
  },
  methods: {
    handleDropdownVisibleChange(visible) {
      if (visible) {
        this.$nextTick(() => {
          const dropdownMenu = document.querySelector('.ant-select-dropdown-menu');
          if (dropdownMenu) {
            dropdownMenu.addEventListener('scroll', this.handleScroll);
          }
        });
      }
    },
    handleScroll(event) {
      console.log('滚动事件触发', event);
      // 处理滚动事件
    }
  }
};
</script>
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题