el-form-renderer-vue3 1.0.7 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,335 +1,335 @@
1
- <template>
2
- <!-- 绑定显示,校验匹配规则字段,label,rules校验规则,attrs(原生属性), -->
3
- <el-form-item
4
- v-if="_show"
5
- :prop="prop"
6
- :label="typeof data.label === 'string' ? data.label : ''"
7
- :rules="!readonly && Array.isArray(data.rules) ? data.rules : undefined"
8
- v-bind="data.attrs"
9
- class="render-form-item"
10
- >
11
- <!-- label插槽 -->
12
- <template #label>
13
- <v-node v-if="data.label !== 'string'" :content="data.label" />
14
- </template>
15
- <!-- 处理之只读input select -->
16
- <template v-if="readonly && hasReadonlyContent">
17
- <el-input
18
- v-if="data.type === 'input'"
19
- v-bind="componentProps"
20
- :modelValue="itemValue"
21
- readonly
22
- v-on="listeners"
23
- />
24
-
25
- <div v-else-if="data.type === 'select'">
26
- {{ multipleValue }}
27
- </div>
28
- </template>
29
- <!-- 处理 date-picker,cascader,动态渲染不显示文字 bug-->
30
- <component
31
- v-else-if="data.type === 'date-picker' || data.type === 'cascader'"
32
- ref="customComponent"
33
- v-bind:is="data.component || `el-${data.type || 'input'}`"
34
- v-bind="componentProps"
35
- :modelValue="itemValue"
36
- :disabled="disabled || componentProps.disabled || readonly"
37
- v-on="listeners"
38
- :loading="loading"
39
- :remote-method="
40
- data.remoteMethod || componentProps.remoteMethod || remoteMethod
41
- "
42
- >
43
- </component>
44
- <!-- 绑定 模板引用 动态组件 props value值 是否禁用 事件 lodding 远端搜索方法 -->
45
- <component
46
- v-else
47
- ref="customComponent"
48
- v-bind:is="data.component || `el-${data.type || 'input'}`"
49
- v-bind="componentProps"
50
- :modelValue="itemValue"
51
- :disabled="disabled || componentProps.disabled || readonly"
52
- v-on="listeners"
53
- :loading="loading"
54
- :remote-method="
55
- data.remoteMethod || componentProps.remoteMethod || remoteMethod
56
- "
57
- >
58
- <!-- 插槽处理 选项-->
59
- <template v-for="(opt, index) in options">
60
- <el-option
61
- v-if="data.type === 'select'"
62
- :key="optionKey(opt) || index"
63
- v-bind="opt"
64
- />
65
- <el-checkbox-button
66
- v-if="data.type === 'checkbox-group' && data.style === 'button'"
67
- :key="opt.value"
68
- v-bind="opt"
69
- :label="'value' in opt ? opt.value : opt.label"
70
- >
71
- {{ opt.label }}
72
- </el-checkbox-button>
73
- <el-checkbox
74
- v-else-if="data.type === 'checkbox-group' && data.style !== 'button'"
75
- :key="opt.value"
76
- v-bind="opt"
77
- :label="'value' in opt ? opt.value : opt.label"
78
- >
79
- {{ opt.label }}
80
- </el-checkbox>
81
- <el-radio-button
82
- v-else-if="data.type === 'radio-group' && data.style === 'button'"
83
- :key="opt.label"
84
- v-bind="opt"
85
- :label="'value' in opt ? opt.value : opt.label"
86
- >{{ opt.label }}</el-radio-button
87
- >
88
- <el-radio
89
- v-else-if="data.type === 'radio-group' && data.style !== 'button'"
90
- :key="opt.label"
91
- v-bind="opt"
92
- :label="'value' in opt ? opt.value : opt.label"
93
- >{{ opt.label }}</el-radio
94
- >
95
- </template>
96
- </component>
97
- </el-form-item>
98
- </template>
99
-
100
- <script setup>
101
- import { computed, reactive, inject, nextTick, ref, watch } from "vue";
102
- import { noop } from "../util/utils";
103
- import getEnableWhenStatus from "../util/enable-when";
104
- import _includes from "lodash.includes";
105
- import _topairs from "lodash.topairs";
106
- import _frompairs from "lodash.frompairs";
107
- import _get from "lodash.get";
108
- // 改用 动态组件 方便获取 ref
109
- // import CustomComponent from "../util/CustomComponent";
110
- import VNode from "../util/VNode";
111
- import axios from "axios";
112
- import {
113
- methodsSymbol,
114
- updateFormsSymbol,
115
- setOptionsSymbol,
116
- } from "../util/keys";
117
- let customComponent = ref();
118
-
119
- let props = defineProps({
120
- data: Object,
121
- prop: {
122
- type: String,
123
- default(rawProps) {
124
- return rawProps.data.id;
125
- },
126
- },
127
-
128
- itemValue: {},
129
- value: Object,
130
- disabled: Boolean,
131
- readonly: Boolean,
132
- options: Array,
133
- });
134
-
135
- // 更新表单方法
136
- const emit = defineEmits(["updateValue"]);
137
- let propsInner = reactive({});
138
-
139
- const loading = ref(false);
140
-
141
- let dataRef = ref(props.data);
142
- // 注入一个由祖先组件或整个应用 (通过 app.provide()) 提供的值。
143
- // 父组件提供 element ui的方法
144
- let methods = inject(methodsSymbol);
145
- // 父组件提供的 更新 options的方法
146
- let setOptions = inject(setOptionsSymbol);
147
- // 是否校验
148
- const isBlurTrigger =
149
- props.data.rules &&
150
- props.data.rules.some((rule) => {
151
- return rule.required && rule.trigger === "blur";
152
- });
153
-
154
- // 计算props
155
- const componentProps = computed(() => ({ ...props.data.el, ...propsInner }));
156
- // 计算是否为只读 input select
157
- const hasReadonlyContent = computed(() =>
158
- ["input", "select"].includes(props.data.type)
159
- );
160
- //执行传入的hidden
161
- const hiddenStatus = computed(() => {
162
- const hidden = props.data.hidden || (() => false);
163
- return hidden(props.value, props.data);
164
- });
165
- // 弃用
166
- const enableWhenStatus = computed(() =>
167
- getEnableWhenStatus(props.data.enableWhen, props.data.value)
168
- );
169
- // 处理组件的显示与隐藏
170
- const _show = computed(() => !hiddenStatus.value && enableWhenStatus.value);
171
- // 处理事件监听 vue3实现 v-model props:modelValue event:update:modelValue
172
- const listeners = computed(() => {
173
- const data = props.data;
174
- const id = data.id;
175
- const atChange = data.atChange || noop;
176
- const on = data.on || {};
177
- const originOnInput = on.input || noop;
178
- const originOnChange = on.change || noop;
179
- const trim = data.trim !== undefined ? data.trim : true;
180
-
181
- let updateForm = inject(updateFormsSymbol);
182
- return {
183
- ..._frompairs(
184
- _topairs(on).map(([eName, handler]) => [
185
- eName,
186
- (...args) => handler(args, updateForm),
187
- ])
188
- ),
189
- // 手动更新表单数据
190
- "update:modelValue": (value, ...rest) => {
191
- if (typeof value === "string" && trim) value = value.trim();
192
- emit("updateValue", { id, value });
193
- // FIXME: rules 的 trigger 只写了 blur,依然会在 change 的时候触发校验!
194
- triggerValidate(id);
195
- },
196
- };
197
- });
198
- // el-select 显示对应的 label;(只读)
199
- const multipleValue = computed(() => {
200
- const multipleSelectValue =
201
- _get(props.data, "el.multiple") && Array.isArray(props.itemValue)
202
- ? props.itemValue
203
- : [props.itemValue];
204
- return multipleSelectValue
205
- .map((val) => (props.options.find((op) => op.value === val) || {}).label)
206
- .join();
207
- });
208
- // 处理服务器获取 options
209
- const makingRequest = (remoteConfig, query) => {
210
- const isOptionsCase =
211
- ["select", "checkbox-group", "radio-group"].indexOf(props.data.type) > -1;
212
- const {
213
- request, //request:用于发起远程请求的函数
214
- prop = "options", // 处理响应数据时的属性名称,默认为 "options" 默认处理 el-cascader 的情况
215
- dataPath = "", //用于指定响应数据中的路径,默认为空字符串
216
- onResponse = (resp) => {
217
- //响应成功时的回调函数,默认为一个函数,用于处理响应数据。
218
- if (dataPath) resp = _get(resp, dataPath);
219
- if (isOptionsCase) {
220
- return resp?.map((item) => ({
221
- label: item[label],
222
- value: item[value],
223
- }));
224
- } else {
225
- return resp;
226
- }
227
- },
228
- onError = (error) => {
229
- //发生错误时的回调函数,默认为一个函数,用于打印错误信息并将 loading.value 设置为 false
230
- console.error(error.message);
231
- loading.value = false;
232
- },
233
- label = "label", //用于选项中的标签属性,默认为 "label"。
234
- value = "value", //用于选项中的值属性,默认为 "value"
235
- } = remoteConfig;
236
- //,表示开始加载数据。
237
- loading.value = true;
238
- //Promise.resolve(request(query)):这里使用 Promise.resolve 包装了 request(query),以确保始终返回一个 Promise 对象。
239
- Promise.resolve(request(query))
240
- // 当请求成功时执行 onResponse 函数,当请求失败时执行 onError 函数。
241
- .then(onResponse, onError)
242
- // .then((resp) => { ... }):在请求完成后,无论成功或失败,都会执行这个 .then 块。在这里,根据 isOptionsCase 的值,对响应数据 resp 进行不同的处理。
243
- .then((resp) => {
244
- // 如果 isOptionsCase 为 true,则将响应数据中的每个元素映射为包含 "label" 和 "value" 属性的对象,并将结果传递给 setOptions 函数(如果存在)。
245
- if (isOptionsCase) {
246
- setOptions && setOptions(props.prop, resp);
247
- } else {
248
- // 如果 isOptionsCase 为 false,则将响应数据存储在 propsInner 中,属性名为 prop。
249
- propsInner = Object.assign(propsInner, { [prop]: resp });
250
- }
251
- // ,表示加载完成。
252
- loading.value = false;
253
- });
254
- };
255
- // 监听 是否有 data
256
- watch(dataRef, (data) => {
257
- if (!data) {
258
- throw new Error("data must be an Object.");
259
- } else if (!data.id) {
260
- throw new Error("`id` is unvalidated.");
261
- } else if (!data.type && !data.component) {
262
- throw new Error("`type` and `component` cannot both be null.");
263
- }
264
- });
265
- // 处理服务器获取options
266
- watch(
267
- /**
268
- * 这里其实用 remote 处理了两件事。有机会是可以拆分的
269
- * 1. 基本用法,配置 url 后即可从远程获取某个 prop 注入到组件
270
- * 2. 针对 select、checkbox-group & radio-group 组件,会直接将 resp 作为 options 处理;label & value 也是直接为这个场景而生的
271
- */
272
- () => props.data.remote?.request,
273
- (newValue, oldValue) => {
274
- // 不应该用 watch data.remote,因为对象引用是同一个 https://cn.vuejs.org/v2/api/#vm-watch (估计当初这样写是为了方便)
275
- // 现改写成:分开处理 remote.request,remote.url
276
- // 至于为什么判断新旧值相同则返回,是因为 form 的 content 是响应式的,防止用户直接修改 content 其他内容时,导致 remote.request 重新发请求
277
-
278
- if (!newValue || typeof newValue !== "function" || newValue === oldValue)
279
- return;
280
-
281
- makingRequest(props.data.remote);
282
- },
283
- { immediate: true }
284
- );
285
- // 处理服务器获取options
286
- watch(
287
- () => props.data.remote?.url,
288
- (url, oldV) => {
289
- // 第三个判断条件:防止 url 与 request 同时存在时,发送两次请求
290
- if (!url || url === oldV || (!oldV && props.data.remote.request)) return;
291
- const request =
292
- props.data.remote.request ||
293
- (() => axios.get(url).then((resp) => resp.data));
294
- makingRequest(Object.assign({}, props.data.remote, { request }));
295
- },
296
- { immediate: true }
297
- );
298
-
299
- // 校验表单项目
300
- const triggerValidate = async (id) => {
301
- try {
302
- if (!props.data.rules || !props.data.rules.length) return;
303
- if (isBlurTrigger) return;
304
- await nextTick();
305
-
306
- (await methods) && methods.validateField(id);
307
- } catch (error) {
308
- console.log(error);
309
- }
310
- };
311
- // 远端搜索方法
312
- const remoteMethod = (query) => {
313
- if (
314
- _get(props.data, "type") === "select" &&
315
- _get(props.data, "el.filterable") &&
316
- _get(props.data, "el.remote")
317
- ) {
318
- makingRequest(props.data.remote, query);
319
- }
320
- };
321
- // 初始化 optios key
322
- const optionKey = (opt) => {
323
- if (opt.value instanceof Object) {
324
- if (!props.data.el || !props.data.el.valueKey) {
325
- return;
326
- }
327
-
328
- return opt.value[props.data.el.valueKey];
329
- } else {
330
- return opt.value;
331
- }
332
- };
333
- // 暴露 element ui 模版引用
334
- defineExpose({ customComponent });
335
- </script>
1
+ <template>
2
+ <!-- 绑定显示,校验匹配规则字段,label,rules校验规则,attrs(原生属性), -->
3
+ <el-form-item
4
+ v-if="_show"
5
+ :prop="prop"
6
+ :label="typeof data.label === 'string' ? data.label : ''"
7
+ :rules="!readonly && Array.isArray(data.rules) ? data.rules : undefined"
8
+ v-bind="data.attrs"
9
+ class="render-form-item"
10
+ >
11
+ <!-- label插槽 -->
12
+ <template #label>
13
+ <v-node v-if="data.label !== 'string'" :content="data.label" />
14
+ </template>
15
+ <!-- 处理之只读input select -->
16
+ <template v-if="readonly && hasReadonlyContent">
17
+ <el-input
18
+ v-if="data.type === 'input'"
19
+ v-bind="componentProps"
20
+ :modelValue="itemValue"
21
+ readonly
22
+ v-on="listeners"
23
+ />
24
+
25
+ <div v-else-if="data.type === 'select'">
26
+ {{ multipleValue }}
27
+ </div>
28
+ </template>
29
+ <!-- 处理 date-picker,cascader,动态渲染不显示文字 bug-->
30
+ <component
31
+ v-else-if="data.type === 'date-picker' || data.type === 'cascader'"
32
+ ref="customComponent"
33
+ v-bind:is="data.component || `el-${data.type || 'input'}`"
34
+ v-bind="componentProps"
35
+ :modelValue="itemValue"
36
+ :disabled="disabled || componentProps.disabled || readonly"
37
+ v-on="listeners"
38
+ :loading="loading"
39
+ :remote-method="
40
+ data.remoteMethod || componentProps.remoteMethod || remoteMethod
41
+ "
42
+ >
43
+ </component>
44
+ <!-- 绑定 模板引用 动态组件 props value值 是否禁用 事件 lodding 远端搜索方法 -->
45
+ <component
46
+ v-else
47
+ ref="customComponent"
48
+ v-bind:is="data.component || `el-${data.type || 'input'}`"
49
+ v-bind="componentProps"
50
+ :modelValue="itemValue"
51
+ :disabled="disabled || componentProps.disabled || readonly"
52
+ v-on="listeners"
53
+ :loading="loading"
54
+ :remote-method="
55
+ data.remoteMethod || componentProps.remoteMethod || remoteMethod
56
+ "
57
+ >
58
+ <!-- 插槽处理 选项-->
59
+ <template v-for="(opt, index) in options">
60
+ <el-option
61
+ v-if="data.type === 'select'"
62
+ :key="optionKey(opt) || index"
63
+ v-bind="opt"
64
+ />
65
+ <el-checkbox-button
66
+ v-if="data.type === 'checkbox-group' && data.style === 'button'"
67
+ :key="opt.value"
68
+ v-bind="opt"
69
+ :label="'value' in opt ? opt.value : opt.label"
70
+ >
71
+ {{ opt.label }}
72
+ </el-checkbox-button>
73
+ <el-checkbox
74
+ v-else-if="data.type === 'checkbox-group' && data.style !== 'button'"
75
+ :key="opt.value"
76
+ v-bind="opt"
77
+ :label="'value' in opt ? opt.value : opt.label"
78
+ >
79
+ {{ opt.label }}
80
+ </el-checkbox>
81
+ <el-radio-button
82
+ v-else-if="data.type === 'radio-group' && data.style === 'button'"
83
+ :key="opt.label"
84
+ v-bind="opt"
85
+ :label="'value' in opt ? opt.value : opt.label"
86
+ >{{ opt.label }}</el-radio-button
87
+ >
88
+ <el-radio
89
+ v-else-if="data.type === 'radio-group' && data.style !== 'button'"
90
+ :key="opt.label"
91
+ v-bind="opt"
92
+ :label="'value' in opt ? opt.value : opt.label"
93
+ >{{ opt.label }}</el-radio
94
+ >
95
+ </template>
96
+ </component>
97
+ </el-form-item>
98
+ </template>
99
+
100
+ <script setup>
101
+ import { computed, reactive, inject, nextTick, ref, watch } from "vue";
102
+ import { noop } from "../util/utils";
103
+ import getEnableWhenStatus from "../util/enable-when";
104
+ import _includes from "lodash.includes";
105
+ import _topairs from "lodash.topairs";
106
+ import _frompairs from "lodash.frompairs";
107
+ import _get from "lodash.get";
108
+ // 改用 动态组件 方便获取 ref
109
+ // import CustomComponent from "../util/CustomComponent";
110
+ import VNode from "../util/VNode";
111
+ import axios from "axios";
112
+ import {
113
+ methodsSymbol,
114
+ updateFormsSymbol,
115
+ setOptionsSymbol,
116
+ } from "../util/keys";
117
+ let customComponent = ref();
118
+
119
+ let props = defineProps({
120
+ data: Object,
121
+ prop: {
122
+ type: String,
123
+ default(rawProps) {
124
+ return rawProps.data.id;
125
+ },
126
+ },
127
+
128
+ itemValue: {},
129
+ value: Object,
130
+ disabled: Boolean,
131
+ readonly: Boolean,
132
+ options: Array,
133
+ });
134
+
135
+ // 更新表单方法
136
+ const emit = defineEmits(["updateValue"]);
137
+ let propsInner = reactive({});
138
+
139
+ const loading = ref(false);
140
+
141
+ let dataRef = ref(props.data);
142
+ // 注入一个由祖先组件或整个应用 (通过 app.provide()) 提供的值。
143
+ // 父组件提供 element ui的方法
144
+ let methods = inject(methodsSymbol);
145
+ // 父组件提供的 更新 options的方法
146
+ let setOptions = inject(setOptionsSymbol);
147
+ // 是否校验
148
+ const isBlurTrigger =
149
+ props.data.rules &&
150
+ props.data.rules.some((rule) => {
151
+ return rule.required && rule.trigger === "blur";
152
+ });
153
+
154
+ // 计算props
155
+ const componentProps = computed(() => ({ ...props.data.el, ...propsInner }));
156
+ // 计算是否为只读 input select
157
+ const hasReadonlyContent = computed(() =>
158
+ ["input", "select"].includes(props.data.type)
159
+ );
160
+ //执行传入的hidden
161
+ const hiddenStatus = computed(() => {
162
+ const hidden = props.data.hidden || (() => false);
163
+ return hidden(props.value, props.data);
164
+ });
165
+ // 弃用
166
+ const enableWhenStatus = computed(() =>
167
+ getEnableWhenStatus(props.data.enableWhen, props.data.value)
168
+ );
169
+ // 处理组件的显示与隐藏
170
+ const _show = computed(() => !hiddenStatus.value && enableWhenStatus.value);
171
+ // 处理事件监听 vue3实现 v-model props:modelValue event:update:modelValue
172
+ const listeners = computed(() => {
173
+ const data = props.data;
174
+ const id = data.id;
175
+ const atChange = data.atChange || noop;
176
+ const on = data.on || {};
177
+ const originOnInput = on.input || noop;
178
+ const originOnChange = on.change || noop;
179
+ const trim = data.trim !== undefined ? data.trim : true;
180
+
181
+ let updateForm = inject(updateFormsSymbol);
182
+ return {
183
+ ..._frompairs(
184
+ _topairs(on).map(([eName, handler]) => [
185
+ eName,
186
+ (...args) => handler(args, updateForm),
187
+ ])
188
+ ),
189
+ // 手动更新表单数据
190
+ "update:modelValue": (value, ...rest) => {
191
+ if (typeof value === "string" && trim) value = value.trim();
192
+ emit("updateValue", { id, value });
193
+ // FIXME: rules 的 trigger 只写了 blur,依然会在 change 的时候触发校验!
194
+ triggerValidate(id);
195
+ },
196
+ };
197
+ });
198
+ // el-select 显示对应的 label;(只读)
199
+ const multipleValue = computed(() => {
200
+ const multipleSelectValue =
201
+ _get(props.data, "el.multiple") && Array.isArray(props.itemValue)
202
+ ? props.itemValue
203
+ : [props.itemValue];
204
+ return multipleSelectValue
205
+ .map((val) => (props.options.find((op) => op.value === val) || {}).label)
206
+ .join();
207
+ });
208
+ // 处理服务器获取 options
209
+ const makingRequest = (remoteConfig, query) => {
210
+ const isOptionsCase =
211
+ ["select", "checkbox-group", "radio-group"].indexOf(props.data.type) > -1;
212
+ const {
213
+ request, //request:用于发起远程请求的函数
214
+ prop = "options", // 处理响应数据时的属性名称,默认为 "options" 默认处理 el-cascader 的情况
215
+ dataPath = "", //用于指定响应数据中的路径,默认为空字符串
216
+ onResponse = (resp) => {
217
+ //响应成功时的回调函数,默认为一个函数,用于处理响应数据。
218
+ if (dataPath) resp = _get(resp, dataPath);
219
+ if (isOptionsCase) {
220
+ return resp?.map((item) => ({
221
+ label: item[label],
222
+ value: item[value],
223
+ }));
224
+ } else {
225
+ return resp;
226
+ }
227
+ },
228
+ onError = (error) => {
229
+ //发生错误时的回调函数,默认为一个函数,用于打印错误信息并将 loading.value 设置为 false
230
+ console.error(error.message);
231
+ loading.value = false;
232
+ },
233
+ label = "label", //用于选项中的标签属性,默认为 "label"。
234
+ value = "value", //用于选项中的值属性,默认为 "value"
235
+ } = remoteConfig;
236
+ //,表示开始加载数据。
237
+ loading.value = true;
238
+ //Promise.resolve(request(query)):这里使用 Promise.resolve 包装了 request(query),以确保始终返回一个 Promise 对象。
239
+ Promise.resolve(request(query))
240
+ // 当请求成功时执行 onResponse 函数,当请求失败时执行 onError 函数。
241
+ .then(onResponse, onError)
242
+ // .then((resp) => { ... }):在请求完成后,无论成功或失败,都会执行这个 .then 块。在这里,根据 isOptionsCase 的值,对响应数据 resp 进行不同的处理。
243
+ .then((resp) => {
244
+ // 如果 isOptionsCase 为 true,则将响应数据中的每个元素映射为包含 "label" 和 "value" 属性的对象,并将结果传递给 setOptions 函数(如果存在)。
245
+ if (isOptionsCase) {
246
+ setOptions && setOptions(props.prop, resp);
247
+ } else {
248
+ // 如果 isOptionsCase 为 false,则将响应数据存储在 propsInner 中,属性名为 prop。
249
+ propsInner = Object.assign(propsInner, { [prop]: resp });
250
+ }
251
+ // ,表示加载完成。
252
+ loading.value = false;
253
+ });
254
+ };
255
+ // 监听 是否有 data
256
+ watch(dataRef, (data) => {
257
+ if (!data) {
258
+ throw new Error("data must be an Object.");
259
+ } else if (!data.id) {
260
+ throw new Error("`id` is unvalidated.");
261
+ } else if (!data.type && !data.component) {
262
+ throw new Error("`type` and `component` cannot both be null.");
263
+ }
264
+ });
265
+ // 处理服务器获取options
266
+ watch(
267
+ /**
268
+ * 这里其实用 remote 处理了两件事。有机会是可以拆分的
269
+ * 1. 基本用法,配置 url 后即可从远程获取某个 prop 注入到组件
270
+ * 2. 针对 select、checkbox-group & radio-group 组件,会直接将 resp 作为 options 处理;label & value 也是直接为这个场景而生的
271
+ */
272
+ () => props.data.remote?.request,
273
+ (newValue, oldValue) => {
274
+ // 不应该用 watch data.remote,因为对象引用是同一个 https://cn.vuejs.org/v2/api/#vm-watch (估计当初这样写是为了方便)
275
+ // 现改写成:分开处理 remote.request,remote.url
276
+ // 至于为什么判断新旧值相同则返回,是因为 form 的 content 是响应式的,防止用户直接修改 content 其他内容时,导致 remote.request 重新发请求
277
+
278
+ if (!newValue || typeof newValue !== "function" || newValue === oldValue)
279
+ return;
280
+
281
+ makingRequest(props.data.remote);
282
+ },
283
+ { immediate: true }
284
+ );
285
+ // 处理服务器获取options
286
+ watch(
287
+ () => props.data.remote?.url,
288
+ (url, oldV) => {
289
+ // 第三个判断条件:防止 url 与 request 同时存在时,发送两次请求
290
+ if (!url || url === oldV || (!oldV && props.data.remote.request)) return;
291
+ const request =
292
+ props.data.remote.request ||
293
+ (() => axios.get(url).then((resp) => resp.data));
294
+ makingRequest(Object.assign({}, props.data.remote, { request }));
295
+ },
296
+ { immediate: true }
297
+ );
298
+
299
+ // 校验表单项目
300
+ const triggerValidate = async (id) => {
301
+ try {
302
+ if (!props.data.rules || !props.data.rules.length) return;
303
+ if (isBlurTrigger) return;
304
+ await nextTick();
305
+
306
+ (await methods) && methods.validateField(id);
307
+ } catch (error) {
308
+ console.log(error);
309
+ }
310
+ };
311
+ // 远端搜索方法
312
+ const remoteMethod = (query) => {
313
+ if (
314
+ _get(props.data, "type") === "select" &&
315
+ _get(props.data, "el.filterable") &&
316
+ _get(props.data, "el.remote")
317
+ ) {
318
+ makingRequest(props.data.remote, query);
319
+ }
320
+ };
321
+ // 初始化 optios key
322
+ const optionKey = (opt) => {
323
+ if (opt.value instanceof Object) {
324
+ if (!props.data.el || !props.data.el.valueKey) {
325
+ return;
326
+ }
327
+
328
+ return opt.value[props.data.el.valueKey];
329
+ } else {
330
+ return opt.value;
331
+ }
332
+ };
333
+ // 暴露 element ui 模版引用
334
+ defineExpose({ customComponent });
335
+ </script>