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