项目中有许多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 表单 组件 中手动写各种输入框了
求大佬指教
<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>
<van-pull-refresh v-model="isLoading" :style="{ height }" success-text="刷新成功" @refresh="onRefresh"> height 在 activated 里修改了一次后,页面并没有监听到变化,为什么?
本文向大家介绍下拉框select的绑定示例,包括了下拉框select的绑定示例的使用技巧和注意事项,需要的朋友参考一下 根据文本绑定text 根据值绑定value
问题内容: 在6.2章的CSS PositionedLayout Module Level(工作草案)中。粘性定位我们有以下定义:(强调我的) 甲粘粘定位的盒类似地定位到一个相对定位的盒子,但计算参考最近的祖先与偏移 滚动框 ,或者如果没有祖先具有视口 滚动框 。 这些滚动框是什么? 在文档的更下方,有一个关于术语的问题 问题6 粘性定位应真正根据最接近的可滚动祖先定义,但是CSS中其他地方目前没
我已经在我的页面上实现了平滑滚动条,它的工作相当不错,但我也想在滚动内容中添加一些过渡效果。基本上,我想在一个滚动事件上做这件事,但我不知道scrollbar的工作有多流畅,以及在滚动事件上执行什么对象。我检查了#my-scrollbar没有执行此操作: 滚动事件的原因是什么?或者有没有其他的方法可以做一些额外的效果而不检查滚动事件? 编辑:我正在粘贴我的代码(我正在使用react.js)来进行更
我有一个vanilla javascript系统在下拉菜单上触发“更改”事件: 它可以通过addEventListener()或$('select').on()完美地处理事件,但如果.on()函数被设置为目标动态元素,它就不起作用了: 我错过了什么?
这个对象里的属性个数和key都是未知的