Iview: Model对话框点击确定后iview会自动关闭窗口

Created on 6 Apr 2017  ·  31Comments  ·  Source: iview/iview

环境:iview 2.0.0-rc.7 vue:2.2.0

问题描述:在某个页面需打开一个Model,然后这个Model里有一个Form表单,点击确定时我需要先校验表单数据是否输入正确,不确定则不希望关闭窗口;(问题是:只要点击确认 loading :false 情况下iview默认就把this.visible = false 窗口就关闭了)

希望楼主优化啊;

看了源码后,目前我这做法是:
Form校验不通过,则:
this.$refs.endorseModel.visible = true;
this.endorseModel = true;
这样窗口就不会关闭;

Most helpful comment

<Modal
    v-model="modal1"
    title="对话框">
  <div slot="footer">
    <Button @click="submit" type="info">提交</Button>
  </div>


自定义页脚,在submit方法中处理,这样比较方便

All 31 comments

+1 昨天正好碰到这个问题

我也遇到这个问题

看了一下,还是使用不当的问题。loading 要动态控制。

<template>
    <div>
        <Button type="primary" @click="modal1 = true">显示对话框</Button>
        <Modal
            v-model="modal1"
            title="普通的Modal对话框标题"
            @on-ok="ok"
            :loading="loading">
            <p>对话框内容</p>
            <p>对话框内容</p>
            <p>对话框内容</p>
        </Modal>
    </div>
</template>
<script>
    export default {
        data () {
            return {
                modal1: false,
                loading: true
            }
        },
        methods: {
            ok () {
                this.$Message.info('异步验证数据');
                setTimeout(() => {
                    this.loading = false;
                    this.$nextTick(() => {
                        this.loading = true;
                    });
                }, 2000);
            }
        }
    }
</script>
<template>
    <div>
        <Button type="primary" @click="modal1 = true">显示对话框</Button>
        <Modal
            v-model="modal1"
            title="普通的Modal对话框标题"
            @on-ok="ok"
            :loading="loading">
            <Form ref="form" :model="form" :rules="rule">
              <Form-item prop="name">
                <Input v-model="form.name"></Input>
              </Form-item>
            </Form>
        </Modal>
    </div>
</template>
<script>
    export default {
        data () {
            return {
                modal1: false,
                loading: true,
                form: {
                  name: ''
                },
                rule: {
                  name: {
                    required: true,
                    min: 4
                  }
                }
            }
        },
        methods: {
          changeLoading() {
            this.loading = false;
            this.$nextTick(() => {
              this.loading = true;
            });
          },
          ok () {
            this.$refs['form'].validate(valid => {
              if(!valid) {
                return this.changeLoading();
              }
              setTimeout(() => {
                this.changeLoading();
                this.modal1 = false;
                this.$Message.success('done');
              }, 1000);
            });
          }
        }
    }
</script>

@icarusion 嗯,试了下 这种方式确实可以;不过文档上没说明,估计一般不知道用这句:
this.$nextTick(() => { this.loading = true; });

菜鸟坑提醒:

export default {
    data() {
        return {
            modal: false,
            loading: true // 一定要设置为true,否则第一次提交表单,modal还是会被隐藏
        }
    }
}

我设置loading: false,害我调试了一下午

在 on-ok 里 return 一个 promise的方式来控制,是不是更合理、直观一些。
虽然通过loading和nextTick配合可以达到目的,但是太绕了,loading属性本身的目的也不是为了这个吧

看来这个设计确实不符合大众使用的习惯,作者可以考虑优化一下吗?

modal 使用起来特别别扭 就这个阻止关闭的这个就设计不好,为什么要强行关闭呢,提供方法出来让开发者自行关闭或许更好

Promise does not make sense to me on this issue. This feature is reasonable that under most of the situations, we wish the modal be closed immediately after clicking the ok button. But we can add a prop autoclose to control whether the modal would be closed when trigger on-ok.

来看async的例子

 this.$refs[name].validate(async (valid) => {
    if (valid) {
      this.loading = false 
      let res= await this.fetchGet('***', {})
      if (res == null) {
        this.$Message.error('*****')
        this.loading = true 
      } else { 
        this.model = false
        this.loading = true
      } 
    } else {
      this.$Message.error('表单验证失败!');
     }
 })

这一点,我觉得有些过度设计了,loading在这里莫名其妙,关闭modal这样的操作,能让开发者自己控制么,与loading裹在一起,不符合开发习惯。

需要先 false loading 再 true loading 才可以重置按钮状态,确实稍微觉得有点不符合开发者思维的使用。把 loading 状态的控制权交还给开发者,这个才比较好。

当然,想手动控制的,都可以用 slot="footer" 自己去重新写一个。

通过
this.$Modal.confirm({loading: true})出来的Modal,
如果想关闭loading,如何做呢?

slot搞不定啊

loading属性只能阻止第一次提交不关闭弹窗,要怎么解决呀?

同感。用起来感觉有点绕。可能是习惯了jQuery那种 return false; 来阻止Modal关闭。

@cuitianze 解决了吗

项目中没有加loading,验证增加了自己的确定取消按钮,然后把model的footer隐藏掉,饶了一个大弯,用验证的按钮控制,Model验证通过关闭,验证不通过确定不关闭

<Form-item class="form">
    <Button type="ghost" size="large" @click="handleCancel()">取消</Button>
    <Button type="primary" size="large" @click="handleSubmit('formValidate')" style="margin-left: 8px">提交</Button>
</Form-item>
<Modal
    v-model="modal1"
    title="对话框">
  <div slot="footer">
    <Button @click="submit" type="info">提交</Button>
  </div>


自定义页脚,在submit方法中处理,这样比较方便

楼上正解

@cuitianze @maplehsu 可以考虑从手动控制添加dom的角度出发,在onOk中添加ivu-btn-loading类和<i class="ivu-load-loop ivu-icon ivu-icon-load-c"></i> <!----> <span>确定</span> html代码,同理在其他地方移除这两样。暂时还想不到其他好的方法,希望官方后续能提供一个方法。

不想出现loading的可以按下面写也能阻止modal关闭

onVideoSelectConfirm(){
  this.loading = false
  let strLink = this.videoLinkInput.trim()
    if (strLink.length < 7 || strLink.substr(0, 4) !== 'http' || strLink.lastIndexOf('.') === -1) {
      this.$Message.error('请输入正确的视频链接')
      this.$nextTick(() => {
        this.loading = true
      })
    } else if(strLink.substr(-4).toLocaleLowerCase() !== '.mp4') {
      this.$Message.error('视频格式必须为mp4格式')
      this.$nextTick(() => {
        this.loading = true
      })
    } else {
      this.$emit('onChangeVideoLink', this.videoLinkInput.trim())
      this.videoSelectShow = false
      this.loading = true
    }
  }

这样可以实现没有loading出现也可以阻止弹窗关闭,videoSelectShow为控制模态框的显示隐藏
loading为控制modal是否有loading,默认值为true,其实icarusion说得挺对的,还是loading没用好

只需要data里面把loading初始化为true, 然后按以下代码,
this.$nextTick(() => { this.loading = true; });
这句是把按钮loding状态去掉的吧.

submit(name) {
      this.loading = false;
      this.$refs[name].validate((valid) => {
        if (valid) {
          this.$Message.success('Success!');
        } else {
          this.$nextTick(() => {
            this.loading = true;
          });
          this.$Message.error('Fail!');
        }
      })
    }

其实不是这样的,真正去掉loading的其实是this.loading = false,这句this.$nextTick(() => { this.loading = true; }只是还原成初始状态,方便下次点击确定按钮会再次出现loading而已

我也遇到这个问题了,modal.$data.buttonLoading = false;可以解决。感觉iview的Modal用起来很不习惯,不过iview的很多用render函数还是比较方便的

this.$Modal.confirm({
        loading: true,
        render: (h) => {
          return (
            <ParameterBuilder item={this.selectedParamComp} />
          )
        },
        onOk: function() {
          let modal = this;
           modal.$data.buttonLoading = false;
        }
      })

nextTick只能阻止一次窗口被关闭,再点一次又关了

点击确定按钮不关闭modal,怎么做,感觉阻止不了哇

还有table组件里面,自定义列的render方法不能直接渲染原生dom结构呢?只能通过h的这种方法么,官方中文文档上是可以直接render返回dom节点呢?

iview的modal太难用了,是我见过最难用的modal

As my view, the callback function of on-ok can be return false if user don't want to close this model dialog.otherwise return true.

loading 控制,多次提交还是会关闭的

Was this page helpful?
0 / 5 - 0 ratings