vue element-ui 第一次打开无法获取dialog里的元素

最近才接触到vue和element.ui,发现element.ui里的dialog有一个问题不知道该怎么解决。
1、例如我在dialog里写了一个表单组件,给表单组件设置了ref为form,在打开dialog的时候需要对里面的表单组件进x行this.$ref['form'].resetFields(),来重置表单。
2、现在发现第一次打开dialog的时候,this.$ref['form']为undefined,关闭dialog,第二次打开之后就可以使用了。
3、有次在打开dialog的事件里写了ajax请求,把重置表单的代码写在success回调里,就没有问题了。
4、尝试用了this.$nextTick(),没有什么用。
希望能有大神看看有什么解决办法。。蟹蟹

--------------------补充分割线-------------------------

dialog部分:

<el-dialog :visible.sync="dialogFormVisible" width="35%">
    <span slot="title" class="el-dialog__title">{{dialogTitle}}</span>
    <el-form :model="form" ref="roomForm" label-position="left" size="small">
    ...
    </el-form>
    <div slot="footer" class="dialog-footer">
    <el-button size="small" @click="dialogFormVisible = false;$refs['roomForm'].resetFields();">取 消</el-button>
    <el-button size="small" type="primary" @click="submitRoom('roomForm')">确 定</el-button>
    </div>
</el-dialog>

点击事件js代码:

modifyRoom(flag, data) {
let self = this;
self.dialogFormVisible = true; //控制dialog 显示
...
// self.$refs[formName].resetFields(); //就是这句代码,可以重置表单(让表单内容回到初始化状态,并清除验证信息)
}

就是我的页面会有新建和修改两个内容,是用同一个dialog实现的,如果点击了修改,就会把已有的数据填入表单内,如果点击新建,就需要重置表单,将表单回复初始状态,但是第一次点击新建的时候,他无法找到表单元素,就无法实现resetFields事件。只要打开一次dialog,第二次就不会报错了。
但是如果我把重置表单那句代码放到ajax请求的success回调函数里,第一次也不会出错。

阅读 14.9k
7 个回答

突然发现自己这么久之前提的问题还没结束,不晓得有没有其他的童鞋们遇到同样的问题,现在贴出我的解决方案,不是唯一的,但是是我现在尝试过没有出现问题的,希望能解决其他宝宝们的问题。
最开始的时候我的弹窗是这样写的

html部分

新增按钮:

<button @click="modifyRoom(0,null)" type="button" class="btn btn-block btn-primary"
                  style="width: 156px;position: absolute;right: 0">
   新增
</button>

修改按钮:

<span @click="modifyRoom(room.id,room)">
   修改
</span>

弹窗部分:

<el-dialog :title='新建/修改' :visible.sync="dialogFormVisible" width="35%">
    <el-form :rules="rules" :model="form" ref="roomForm" label-position="left" size="small">
        ....
    </el-form>
    <div slot="footer" class="dialog-footer">
      <el-button size="small" @click="dialogFormVisible = false;$refs['roomForm'].resetFields();">
          取 消
      </el-button>
      <el-button size="small" type="primary" @click="submitRoom('roomForm')">
          确 定
      </el-button>
    </div>
</el-dialog>

methods:
新建或修改:
modifyRoom(flag, data) {
  let self = this;
  self.dialogFormVisible = true;
  self.submitFlag = flag;
  self.$refs['roomForm'].resetFields(); //打开弹窗的时候重置弹窗数据,将所有的数据恢复初始值并移除所有的验证信息
  if (flag == 0){
    self.dialogTitle = '新增';
  }else{
    self.dialogTitle = '修改';
    self.form.name = data.name;
    self.form.state = data.state;
    self.form.number = data.number;
    self.form.remark = data.remark;
  }
},

这时候就要看一下elementUI对于dialog的解释了
elementUI-dialog

由于懒加载,所以在第一次打开dialog之前,dialog是没有被渲染成dom元素的
所以就会造成第一次打开dialog的时候提示resetFields为undefined了
第一次打开dialog无法获取dialog元素

然后尝试了几种方法

1. 异步加载
因为我之前有做过打开弹窗之后就请求数据,然后在成功回调里用resetFields方法,
可以成功,也不会出现问题,然后我就用了$nextTick()方法

modifyRoom(flag, data) {
    ...
    self.$nextTick(()=>{
        self.$refs['roomForm'].resetFields(); 
    })
    if(...){
        ...
    }else{
        ...
    }
    ...
};

出现的问题是,回填时会有某些数据无法回填的问题,先点击编辑再点击新增会出现缓存问题
2、单独清空新增,修改直接数据覆盖
modifyRoom(flag, data) {
    ...
    if(...){
       self.$nextTick(()=>{
            self.$refs['roomForm'].resetFields(); 
       })
    }else{
        ...
    }
    ...
};
和1同样的问题,会有数据缓存的问题,而且还很随机
3、直接将数据重新覆盖为初始值
这样做的坏处有很多,如果弹窗中数据很多的话,会造成代码冗余
而且不能清除验证消息,但是只有3是能保证没有问题的,所以最后的解决方案是在3的基础上进行了优化

最后的解决方案是,将弹窗数据提出来,新建一个弹窗vue文件
直接把弹窗对象写成一个const(记得要export),然后在要用的页面引入弹窗vue文件
data里直接把弹窗对象new出来,然后新建的时候重新new一个,关闭弹窗的时候调用resetFields方法
就能完美的解决这个问题了,而且可复用性也很强,要用的时候直接引入就行了

弹窗部分:

<el-dialog :title='新建/修改' :visible.sync="dialogFormVisible" width="35%" 
@close="$refs['roomForm'].resetFields();">
    <el-form :rules="rules" :model="form" ref="roomForm" label-position="left" size="small">
        ....
    </el-form>
    <div slot="footer" class="dialog-footer">
      <el-button size="small" @click="dialogFormVisible = false;$refs['roomForm'].resetFields();">
          取 消
      </el-button>
      <el-button size="small" type="primary" @click="submitRoom('roomForm')">
          确 定
      </el-button>
    </div>
</el-dialog>

import Vo from '../dialogForm.vue'
data(){
    return {
       dialogList:new Vo.dialogList();
    }
},
methods:
modifyRoom(flag, data) {
  let self = this;
  self.dialogFormVisible = true;
  self.submitFlag = flag;
  if (flag == 0){
    self.dialogTitle = '新增';
    self.dialogList = new Vo.dialogList();
  }else{
    self.dialogTitle = '修改';
    self.form.name = data.name;
    self.form.state = data.state;
    self.form.number = data.number;
    self.form.remark = data.remark;
  }
},

dialogForm.vue
<script>
    const dialogList = () => {
        return {
          name:'',
          state:'',
          number:'',
          remark:'',
        }
    }
  export default {
    name: 'dialog-form',
    dialogList
  }
</script>

这样写就可以很好的解决我之前提出的问题,感谢 懒懒的技术宅 同学给我的灵感,希望能给以后遇到这个问题的人一些帮助

新手上路,请多包涵

setTimeout(() => {

self.$refs[formName].resetFields()

}, 0)

看了好几遍,老哥,贴出你的代码吧

楼主最后咋解决的,求分享

新手上路,请多包涵

我的在chrome浏览器没有问题,在IE上有这个问题,nextclick页面没用,,,咋解决

新手上路,请多包涵

再给一个解决方案:

this.visible = true
// 必须在弹窗打开后调用
this.$nextTick(() => {
 this.$refs['form'].resetFields()
})

在重置之前,给 visible 属性赋值

在mounted函数里面加上一行,让dialog不再懒加载,就能获取到啦。
this.$refs.yourDialog.rendered=true

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题