彻底解决Error in nextTick: TypeError: Cannot read properties of undefined (reading clearValidate)

背景描述

最近在做国际化的功能,然后就发现各种问题,最开始是rules在国际化中不随着语言的变化而变化,为了解决这个问题开始踩坑……

错误日志

vue.runtime.esm.js:619  [Vue warn]: Error in nextTick: "TypeError: Cannot read properties of undefined (reading 'clearValidate')"

found in

---> <Device>
       <Device> at src/views/flowinn/device/index.vue
         <AppMain> at src/layout/components/AppMain.vue
           <Layout> at src/layout/index.vue
             <App> at src/App.vue
               <Root>
warn @ vue.runtime.esm.js:619
vue.runtime.esm.js:1888  TypeError: Cannot read properties of undefined (reading 'clearValidate')
    at VueComponent.eval (VM5890 deviceAdd.vue:136:32)
    at Array.eval (vue.runtime.esm.js:1980:1)
    at flushCallbacks (vue.runtime.esm.js:1906:1)

解决方法

把this.$nextTick换成this.$forceUpdate即可解决。

使用了forceUpdate,如果是在引入的页面中使用了该方法,记得resetForm,不然弹出框重新打开后,那个错误的message还是在提示。

-------------------------以下是rules不同情况下的使用方法-------------------------------

在下面的几种情况中,都只用到了nextTick和forceUpdate方法,并没有使用resetFields方法。经过验证resetFields方法有问题,有时候会导致部分的input无法输入,切记不要使用。在网上搜索了一下发现有使用setTimeout方法的,那些基本是做赋值用的,这里还是不适用,经过测试完全没有效果。

第一种情况

这种情况下不需要国际化,只是一个简单的form表单验证,而且不是引入的页面或组件,就是一个完整的单一页面。这种情况下直接在data中定义自己的rules就可以实现功能。

data() {
    return {
      inputDisabled: true,
      title:"",
      addErrorMessage:"",
      addOpen: false,
      // 分组选项
      queryGroupOptions: [],
      // 用户选项
      queryUserOptions: [],
      // 表单参数
      addForm: {
        id:null,
        devId:"",
        ownerId:"",
        name:"",
        devDesc:"",
        longitude:"",
        latitude:"",
        groupId:"",
      },
      rules: {
        devId: [
          { required: true, message: '请输入用户账号', trigger: 'blur' }
        ],
      }
    };
  },

第二种情况

需要实现国际化功能,但是不是引入的页面或组件,就是一个完整的单一页面。这种情况下需要借助nextTick方法来实现。在这种情况下,如果使用第一种写法,就会出现一个问题,就是你切换了不同的语言,这时候输入框的不填写时候的错误消息还是默认的中文的,不会随着语言的切换而切换。

export default {
  name: "Device",
  data() {
    return {
      inputDisabled: true,
      title:"",
      addErrorMessage:"",
      addOpen: false,
      // 分组选项
      queryGroupOptions: [],
      // 用户选项
      queryUserOptions: [],
      // 表单参数
      addForm: {
        id:null,
        devId:"",
        ownerId:"",
        name:"",
        devDesc:"",
        longitude:"",
        latitude:"",
        groupId:"",
      },
    };
  },
  computed: {
    rules() {
      let rules = {
        devId: [
          { required: true, message: this.$i18n.t('userInput')+this.$i18n.t('indexTablePrimaryKey'), trigger: 'blur' }
        ],
      };
      // 引入的页面必须使用forceUpdate, 单一的页面中可以直接使用nextTick
      this.$nextTick( () => {
        this.$refs['addForm'].clearValidate();
      });
      return rules;
    }
  },
}

第三种情况

需要实现国际化功能,是引入的页面或组件。这种情况下需要借助forceUpdate方法来实现。

这种方法下特别要注意,功能虽然实现了,但是出现了另一个问题。就是弹出框打开后,鼠标离开输入框,错误消息提示,然后关闭弹出框,再次打开弹出框的时候,那个错误消息还在,这时候需要调用resetForm来解决。以下的代码中都有。

export default {
  name: "Device",
  data() {
    return {
      inputDisabled: true,
      title:"",
      addErrorMessage:"",
      addOpen: false,
      // 分组选项
      queryGroupOptions: [],
      // 用户选项
      queryUserOptions: [],
      // 表单参数
      addForm: {
        id:null,
        devId:"",
        ownerId:"",
        name:"",
        devDesc:"",
        longitude:"",
        latitude:"",
        groupId:"",
      },
    };
  },
  computed: {
    rules() {
      let rules = {
        devId: [
          { required: true, message: this.$i18n.t('userInput')+this.$i18n.t('indexTablePrimaryKey'), trigger: 'blur' }
        ],
      };
      // 引入的页面必须使用forceUpdate, 单一的页面中可以直接使用nextTick
      this.$forceUpdate( () => {
        this.$refs['addForm'].clearValidate();
      });
      return rules;
    }
  },
    dialogAddOpenFun(chooseId){
      this.addErrorMessage = "";
      noPageListUser().then(response => {
        this.queryUserOptions = response.rows;
      });
      listBsGroupNoPage().then(response => {
        this.queryGroupOptions = response.rows;
      });
      if(chooseId == null){
        this.inputDisabled = false;
        this.title = this.$i18n.t('btnAdd');
        this.addForm.id=null,
        this.addForm.devId="";
        this.addForm.ownerId="";
        this.addForm.name="";
        this.addForm.devDesc="";
        this.addForm.longitude="";
        this.addForm.latitude="";
        this.addForm.groupId="";
    // 特别重要
        this.resetForm("addForm");
      }else{
        this.inputDisabled = true;
        this.title = this.$i18n.t('btnEdit');
        this.addForm.devId=chooseId;
        getDevice(chooseId).then(response => {
          this.addForm = response.data;
        });
      }
      this.addOpen = true;
    },
}

vue完整代码

<template>
    <!-- 新增或编辑 -->
    <el-dialog 
      :title="title" 
      :visible.sync="addOpen" 
      :close-on-click-modal="false"
      width="660px" append-to-body>
      <div class="deviceAddOutDiv">
        <el-form ref="addForm" :model="addForm" :rules="rules" label-width="100px" @submit.native.prevent>
          <el-row>
            <el-col :span="24">
              <div style="height: 30px; color: #f56c6c;text-align: center;">{{addErrorMessage}}</div>
            </el-col>
          </el-row>
          <el-row>
            <el-col :span="24">
              <el-form-item :label="$t('indexTablePrimaryKey')" prop="devId">
                <el-input v-model="addForm.devId" :disabled="inputDisabled" :maxlength="60" auto-complete="off" 
                :placeholder="`${this.$t('userInput')}${this.$t('indexTablePrimaryKey')}`" style="width: 100%;" />
              </el-form-item>
            </el-col>
          </el-row>
          <el-row>
            <el-col :span="24">
              <el-form-item :label="$t('indexTableDeviceName')" prop="name">
                <el-input v-model="addForm.name" :maxlength="120" auto-complete="off" :placeholder="`${this.$t('userInput')}${this.$t('indexTableDeviceName')}`" style="width: 100%;" />
              </el-form-item>
            </el-col>
          </el-row>
          <el-row>
            <el-col :span="24">
              <el-form-item :label="$t('deviceDescription')" prop="devDesc">
                <el-input v-model="addForm.devDesc" :maxlength="120" auto-complete="off" :placeholder="`${this.$t('userInput')}${this.$t('deviceDescription')}`" style="width: 100%;" />
              </el-form-item>
            </el-col>
          </el-row>
          <el-row>
            <el-col :span="24">
              <el-form-item :label="$t('deviceGroup')" prop="groupId">
                <el-select v-model="addForm.groupId" filterable clearable :placeholder="`${this.$t('userChoose')}${this.$t('deviceGroup')}`" style="width: 100%;">
                  <el-option
                    v-for="item in queryGroupOptions"
                    :key="item.id"
                    :label="item.name"
                    :value="item.id"
                  ></el-option>
                </el-select>
              </el-form-item>
            </el-col>
          </el-row>
          <el-row>
            <el-col :span="24">
              <el-form-item :label="$t('deviceCreate')" prop="ownerId">
                <el-select v-model="addForm.ownerId" filterable clearable :placeholder="`${this.$t('userChoose')}${this.$t('deviceCreate')}`" style="width: 100%;">
                  <el-option
                    v-for="item in queryUserOptions"
                    :key="item.id"
                    :label="`${item.deptName} / ${item.account}`"
                    :value="item.id"
                  ></el-option>
                </el-select>
              </el-form-item>
            </el-col>
          </el-row>
          <el-row>
            <el-col :span="12">
              <el-form-item :label="$t('deviceLongitude')" prop="longitude">
                <el-input v-model="addForm.longitude" :maxlength="18" auto-complete="off" :placeholder="`${this.$t('userInput')}${this.$t('deviceLongitude')}`"  />
              </el-form-item>
            </el-col>
            <el-col :span="12">
              <el-form-item :label="$t('deviceLatitude')" prop="latitude">
                <el-input v-model="addForm.latitude" :maxlength="18" auto-complete="off" :placeholder="`${this.$t('userInput')}${this.$t('deviceLatitude')}`" />
              </el-form-item>
            </el-col>
          </el-row>
        </el-form>
      </div>
      
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogAddCloseFun">{{$t("btnCancel")}}</el-button>
        <el-button type="primary" @click="deviceAddSubmitForm">{{$t("btnConfirm")}}</el-button>
      </div>
    </el-dialog>


</template>

<script>
import { listBsGroupNoPage } from "@/api/flowinn/group";
import { noPageListUser } from "@/api/flowinn/user";
import { getDevice, addDevice, updateDevice } from "@/api/flowinn/device";

export default {
  name: "Device",
  data() {
    return {
      inputDisabled: true,
      title:"",
      addErrorMessage:"",
      addOpen: false,
      // 分组选项
      queryGroupOptions: [],
      // 用户选项
      queryUserOptions: [],
      // 表单参数
      addForm: {
        id:null,
        devId:"",
        ownerId:"",
        name:"",
        devDesc:"",
        longitude:"",
        latitude:"",
        groupId:"",
      },
    };
  },
  computed: {
    rules() {
      let rules = {
        devId: [
          { required: true, message: this.$i18n.t('userInput')+this.$i18n.t('indexTablePrimaryKey'), trigger: 'blur' }
        ],
      };
      this.$forceUpdate( () => {
        this.$refs['addForm'].clearValidate();
      });
      return rules;
    }
  },
  created() {
    
  },
  methods: {
    
    dialogAddOpenFun(chooseId){
      this.addErrorMessage = "";
      noPageListUser().then(response => {
        this.queryUserOptions = response.rows;
      });
      listBsGroupNoPage().then(response => {
        this.queryGroupOptions = response.rows;
      });
      if(chooseId == null){
        this.inputDisabled = false;
        this.title = this.$i18n.t('btnAdd');
        this.addForm.id=null,
        this.addForm.devId="";
        this.addForm.ownerId="";
        this.addForm.name="";
        this.addForm.devDesc="";
        this.addForm.longitude="";
        this.addForm.latitude="";
        this.addForm.groupId="";
        // 特别重要,不然弹出框的rules消息一直不消失
        this.resetForm("addForm");
      }else{
        this.inputDisabled = true;
        this.title = this.$i18n.t('btnEdit');
        this.addForm.devId=chooseId;
        getDevice(chooseId).then(response => {
          this.addForm = response.data;
        });
      }
      this.addOpen = true;
    },
    dialogAddCloseFun(){
      this.addOpen = false;
    },
    deviceAddSubmitForm(){
      this.$refs["addForm"].validate(valid => {
        if (valid) {
          if (this.addForm.id != null) {
            updateDevice(this.addForm).then(response => {
              if(response.code != 200){
                this.addErrorMessage = this.$i18n.t('wordErrorStart')+response.msg;
              }else{
                this.$modal.msgSuccess(this.$i18n.t('messageUpdateSuccess'));
                this.addOpen = false;
                this.$parent.getList();
              }
            });
          } else {
            addDevice(this.addForm).then(response => {
              if(response.code != 200){
                this.addErrorMessage = this.$i18n.t('wordErrorStart')+response.msg;
              }else{
                this.$modal.msgSuccess(this.$i18n.t('messageAddSuccess'));
                this.addOpen = false;
                this.$parent.getList();
              }
            });
          }
        }
      });
    },
  },
  
  mounted() {
    
  }
};

</script>

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
DeepSpeed命令参数是指在启动容器时使用的命令参数,用于配置DeepSpeed库和Megatron-Deepspeed的相关设置。根据引用的内容,以下是DeepSpeed命令参数的解释: - -d: 启用后台模式 (detached mode),容器将在后台运行。 - -t: 分配一个伪终端 (pseudo-TTY),使得用户可以与容器进行交互。 - --network=host: 使用主机网络模式,容器将共享主机的网络命名空间。 - --gpus all: 分配所有可用的GPU给容器使用。 - --privileged: 赋予容器完全的特权,使其可以访问主机的设备。 - --ipc=host: 使用与主机共享的IPC命名空间,用于进程间通信。 - --ulimit memlock=-1: 设置内存锁定的限制为无限制,以防止内存被交换出去。 - --ulimit stack=67108864: 设置栈的限制为67108864字节,用于控制进程的栈空间。 - --name megatron-deepspeed: 为容器指定一个名称。 - -v /etc/localtime:/etc/localtime: 将主机的时区信息挂载到容器内部,以保持时间同步。 - -v /root/.ssh:/root/.ssh: 将主机的SSH配置目录挂载到容器内部,以便容器可以访问SSH密钥。 - nvcr.io/nvidia/pytorch:21.10-py3: 指定使用的Docker镜像,这里使用了nvcr.io/nvidia/pytorch的21.10-py3版本。 综上所述,以上是DeepSpeed命令参数的解释。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [阿里云AIGC- 使用Megatron-Deepspeed训练GPT-2并生成文本](https://blog.csdn.net/qq_39970492/article/details/131090026)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

renkai721

谢谢您的打赏!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值