关于vue中$nextTick的一点使用心得

当下公司在做一个媒体门户网站,后台由另一家公司使用java开发并提供接口,本人负责开发后台页面,使用的是vue-element-admin开发

下面说一下问题场景,在开发过程中有一个后台管理员角色页面,其中包含一个表单dialog,在其中使用了el-tree组件,相关 代码结构如下:

<div class="filter-container">
    <el-button class="filter-item" style="margin-left: 10px;" v-waves @click="handleCreate" type="primary" icon="el-icon-edit">新增角色
    </el-button>
</div>
<el-dialog :title="textMap[dialogStatus]" :visible.sync="dialogFormVisible" width="50%">
  <el-form :rules="rules" ref="dataForm" :model="temp" label-position="top" label-width="90px"
           style='width: 400px; margin-left:50px;'>
      <el-form-item label="选择权限" prop="sysPermission">
          <el-tree ref="tree" :data="sysPermission" :props="formProps" show-checkbox
                   @check-change="handleCheckChange" node-key="id"></el-tree>
      </el-form-item>
  </el-form>
</el-dialog>

相关的js如下:

export default {
        name: 'sysRoleList',
        data() {
            return {
                tableKey: 0,
                list: null,
                total: null,
                listLoading: true,
                formLoading: true,
                listQuery: {
                    page: 1,
                    limit: 20,
                    importance: undefined,
                    title: undefined,
                    type: undefined,
                    sort: '+id'
                },
                dialogFormVisible: false,
                dialogStatus: 'update',
                textMap: {
                    update: '编辑角色',
                    create: '新增角色'
                },
                rules: {
                    sysRoleName: [{required: true, message: '必须填写角色名称', trigger: 'blur'}]
                },
                // 表单数据
                temp: {
                    id: '',
                    sysPermissionList: [],
                    sysRoleName: ''
                },
                currentKeys: [],
                // 表单权限字段映射
                formProps: {
                    label: 'sysPermissionName'
                },
                sysPermission: {}
            }
        },
        created() {
            // 列表数据
            // this.getList()
            // 获取所有权限
            // this.findAllSysPermission()
        },
        methods: {
            /*
            * todo:checkbox状态变更监听
            * */
            handleCheckChange(data, checked, indeterminate) {
                const idObj = {id: data.id}
                this.temp.sysPermissionList.push(idObj)
            },
            resetTemp() {
                this.temp = {
                    id: '',
                    sysRoleName: '',
                    sysPermissionList: []
                }
            },
            handleCreate() {
                this.resetTemp()
                this.dialogStatus = 'create'
                this.currentKeys = []
                this.dialogFormVisible = true
                this.$nextTick(() => {
                    this.$refs['dataForm'].clearValidate()
                    this.$refs.tree.setCheckedKeys(this.currentKeys)
                })
            },
            handleUpdate(row) {
                this.resetTemp()
                this.dialogStatus = 'update'
                this.dialogFormVisible = true
                this.temp = Object.assign({}, row) // copy obj
                this.currentKeys = []
                row.sysPermissionList.forEach((value, index) => {
                    this.currentKeys.push(value[0])
                })
                this.$nextTick(() => {
                    this.$refs['dataForm'].clearValidate()
                    this.$refs.tree.setCheckedKeys(this.currentKeys)
                })
            }
        }
    }

需求:

需要在每次编辑数据的时候触发<el-tree>的方法setCheckedKeys

问题:

之前没有把this.$refs.tree.setCheckedKeys()写在this.$nextTick的callback之中,因此会提示:

TypeError: Cannot read property 'setCheckedKeys' of undefined

解决方法:

把dialog组件内的其他需要执行方法的组件方法写到this.$nextTick的callback之中

原因如下(官方):

可能你还没有注意到,Vue 异步执行 DOM 更新。只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作上非常重要。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。Vue 在内部尝试对异步队列使用原生的 Promise.then 和 MessageChannel,如果执行环境不支持,会采用 setTimeout(fn, 0) 代替。

例如,当你设置 vm.someData = ‘new value’ ,该组件不会立即重新渲染。当刷新队列时,组件会在事件循环队列清空时的下一个“tick”更新。多数情况我们不需要关心这个过程,但是如果你想在 DOM 状态更新后做点什么,这就可能会有些棘手。虽然 Vue.js 通常鼓励开发人员沿着“数据驱动”的方式思考,避免直接接触 DOM,但是有时我们确实要这么做。为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用 Vue.nextTick(callback) 。这样回调函数在 DOM 更新完成后就会调用。

深入响应式原理

个人理解:

vue这么做是因为频繁的更新dom是特别耗费性能的,所以搞了一个批处理更新,把所有的update操作放到任务队列中,等主线程中执行栈的所有同步任务执行完毕,系统就会读取任务队列

一个比较典型的场景,created回调里是无法直接通过this.$refs获取到用ref命名的子组件的,只有通过$nextTick才能访问到。还有比如dialog里有一个步骤条组件,在每次打开对话框都想触发步骤1的动作。如果直接写step=0;step=1;是不会有变化的,因为整个函数执行完之前DOM都不会刷新。把step=1放到$nextTick里就可以了

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏smy

微信小程序避坑指南

 详见官方文档:https://developers.weixin.qq.com/miniprogram/dev/framework/client-lib/cl...

59630
来自专栏葡萄城控件技术团队

Webpack4干货分享:第一部分,入口、输入和ES6模块

转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。

11420
来自专栏闰土大叔

入职第三天:vue-loader在项目中是如何配置的

这是我入职第三天的故事,在写这篇文章之前,先来看看咱们今天要讲的主角——vue-loader,你对它了解多少?

12110
来自专栏前端开发

PWA介绍及快速上手搭建一个PWA应用

一个新的前端技术,PWA( 全称:Progressive Web App )也就是说这是个渐进式的网页应用程序。

498130
来自专栏静下来

设置wordpress文章标题在新标签打开

这个问题我也是今天才发现,我这个网站的标题是在当前页面打开的。 我个人是一直不喜欢这种打开方式的,不管是我自己的网站,还是别人的某些网站。 我觉得这样,有时...

41140
来自专栏静默虚空的博客

Webpack 代码分离

Webpack 代码分离 ? 提示: 1、版本问题 本文基于 webpack 2.x 版本。webpack 2.x 相比 webpack 1.x 有重大...

31770
来自专栏vue学习

7、reset.css的引入及1px边框问题的解决

因为不同的浏览器默认的样式不同,所以在着手项目开始前,我们需要引入reset.css,将所有html标签的默认样式统一化。我这里推荐一个下载reset.css的...

14820
来自专栏iOS Developer

微信小程序开发教程-从零开始(3)

25060
来自专栏源码之家

Apache启动后又停止的解决办法

今天星期天,加班,但没什么工作任务,本打算好好把武术藏经阁网站搞一搞,没想到打开电脑,却是APACHE无法启动,找了半天,以前一般都是端口占用情况,今天改了端口...

40120
来自专栏陈纪庚

微信小程序bug记录与解决

第一张图是在开发工具上的,第二张图是在IOS真机上的。从上图可以看出来,在开发工具上显示很正常,而且没有padding,可是在真机上左上角就出现了paddi...

31020

扫码关注云+社区

领取腾讯云代金券