Skip to content

Commit 5b585fa

Browse files
author
levy
committed
Merge branch 'dev'
2 parents c99b857 + 247baf3 commit 5b585fa

File tree

3 files changed

+79
-42
lines changed

3 files changed

+79
-42
lines changed

cypress/integration/remote.spec.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ describe('测试 remote 示例', function() {
66
cy.$goto('remote')
77
})
88
it('测试所有 remote 配置', function() {
9-
cy.$getFormItemInput('select').click()
9+
cy.$getFormItemInput('select')
10+
.click()
11+
.type('input')
1012
cy.contains('area1').click()
1113
cy.contains('resourceA')
1214
cy.contains('typeA')

docs/remote.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<script>
1111
export default {
1212
data () {
13+
let getRemoteUrl = (query) => 'https://mockapi.eolinker.com/IeZWjzy87c204a1f7030b2a17b00f3776ce0a07a5030a1b/el-form-renderer?q=remote&input=' + query
1314
return {
1415
content: [
1516
// 只需要设置 url,即可远程配置 options
@@ -18,7 +19,15 @@ export default {
1819
id: 'select',
1920
label: 'select',
2021
remote: {
21-
url: 'https://mockapi.eolinker.com/IeZWjzy87c204a1f7030b2a17b00f3776ce0a07a5030a1b/el-form-renderer?q=remote',
22+
url: ''
23+
},
24+
el: {
25+
placeholder: '请输入,会发请求',
26+
filterable: true,
27+
remote: true,
28+
remoteMethod: query => {
29+
this.content[0].remote.url = getRemoteUrl(query)
30+
}
2231
}
2332
},
2433
// 可以自定义 request 方法,做各种操作
@@ -27,6 +36,7 @@ export default {
2736
id: 'radio',
2837
label: 'radio',
2938
remote: {
39+
url: 'fake.url', // 同时存在 url 与 request, 以后者为准
3040
request() {
3141
const resp = {
3242
path: [
@@ -73,8 +83,8 @@ export default {
7383
request() {
7484
return [
7585
{
76-
label: 'hello',
77-
value: 'hello',
86+
label: 'hello',
87+
value: 'hello',
7888
children: [
7989
{
8090
label: 'world',

src/components/render-form-item.vue

Lines changed: 63 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
v-bind="componentProps"
3434
:value="itemValue"
3535
:disabled="disabled || componentProps.disabled || readonly"
36+
:loading="loading"
3637
v-on="listeners"
3738
>
3839
<template v-for="(opt, index) in options">
@@ -116,6 +117,7 @@ export default {
116117
},
117118
data() {
118119
return {
120+
loading: false,
119121
propsInner: {},
120122
isBlurTrigger:
121123
this.data.rules &&
@@ -195,45 +197,27 @@ export default {
195197
* 1. 基本用法,配置 url 后即可从远程获取某个 prop 注入到组件
196198
* 2. 针对 select、checkbox-group & radio-group 组件,会直接将 resp 作为 options 处理;label & value 也是直接为这个场景而生的
197199
*/
198-
'data.remote': {
200+
'data.remote.request': {
199201
handler(v, oldV) {
200-
if (!v) return
201-
if (oldV) {
202-
if (v.url === oldV.url || v.request === oldV.request) return
203-
}
204-
const isOptionsCase =
205-
['select', 'checkbox-group', 'radio-group'].indexOf(this.data.type) >
206-
-1
207-
const {
208-
url,
209-
request = () => this.$axios.get(url).then(resp => resp.data),
210-
prop = 'options', // 默认处理 el-cascader 的情况
211-
dataPath = '',
212-
onResponse = resp => {
213-
if (dataPath) resp = _get(resp, dataPath)
214-
if (isOptionsCase) {
215-
return resp.map(item => ({
216-
label: item[label],
217-
value: item[value],
218-
}))
219-
} else {
220-
return resp
221-
}
222-
},
223-
onError = error => console.error(error.message),
224-
label = 'label',
225-
value = 'value',
226-
} = v
227-
Promise.resolve(request())
228-
.then(onResponse, onError)
229-
.then(resp => {
230-
if (isOptionsCase) {
231-
this.elFormRenderer &&
232-
this.elFormRenderer.setOptions(this.prop, resp)
233-
} else {
234-
this.propsInner = {[prop]: resp}
235-
}
236-
})
202+
// 不应该用 watch data.remote,因为对象引用是同一个 https://cn.vuejs.org/v2/api/#vm-watch (估计当初这样写是为了方便)
203+
// 现改写成:分开处理 remote.request,remote.url
204+
// 至于为什么判断新旧值相同则返回,是因为 form 的 content 是响应式的,防止用户直接修改 content 其他内容时,导致 remote.request 重新发请求
205+
if (!v || typeof v !== 'function' || v === oldV) return
206+
this.makingRequest(this.data.remote)
207+
},
208+
immediate: true,
209+
},
210+
/**
211+
* 设计意图:外部修改 url, 重新发送请求。如果同时存在 url 与 request,则请 request 为准。
212+
*/
213+
'data.remote.url': {
214+
handler(url, oldV) {
215+
// 第三个判断条件:防止 url 与 request 同时存在时,发送两次请求
216+
if (!url || url === oldV || (!oldV && this.data.remote.request)) return
217+
const request =
218+
this.data.remote.request ||
219+
(() => this.$axios.get(url).then(resp => resp.data))
220+
this.makingRequest(Object.assign({}, this.data.remote, {request}))
237221
},
238222
immediate: true,
239223
},
@@ -258,6 +242,47 @@ export default {
258242
return opt.value
259243
}
260244
},
245+
makingRequest(remoteConfig) {
246+
const isOptionsCase =
247+
['select', 'checkbox-group', 'radio-group'].indexOf(this.data.type) > -1
248+
const {
249+
request,
250+
prop = 'options', // 默认处理 el-cascader 的情况
251+
dataPath = '',
252+
onResponse = resp => {
253+
if (dataPath) resp = _get(resp, dataPath)
254+
if (isOptionsCase) {
255+
return resp.map(item => ({
256+
label: item[label],
257+
value: item[value],
258+
}))
259+
} else {
260+
return resp
261+
}
262+
},
263+
onError = error => {
264+
console.error(error.message)
265+
this.loading = false
266+
},
267+
label = 'label',
268+
value = 'value',
269+
} = remoteConfig
270+
271+
this.loading = true
272+
273+
Promise.resolve(request())
274+
.then(onResponse, onError)
275+
.then(resp => {
276+
if (isOptionsCase) {
277+
this.elFormRenderer &&
278+
this.elFormRenderer.setOptions(this.prop, resp)
279+
} else {
280+
this.propsInner = {[prop]: resp}
281+
}
282+
283+
this.loading = false
284+
})
285+
},
261286
},
262287
}
263288
</script>

0 commit comments

Comments
 (0)