文章目录

  • 1 问题描述
  • 2 问题分析
  • 3 解决方案
    • 3.1 将元素放在 footer slot 中
    • 3.2 在 open 事件中延迟执行具体的代码
    • 3.3 在 update 回调函数执行相关的逻辑
    • 3.4 主动更改 rendered 的值为 true

1 问题描述

使用 Element UI dialog 组件,在 dialog 对话框中渲染图表,需要获取图表挂载点的 dom 元素。由于 Element UI 的 dialog_body 是以 lazy 模式进行渲染,导致 dialog 打开时,图表加载失败!

示例页面

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><!-- import CSS --><link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
</head>
<body><div id="app"><el-button @click="visible = true">Button</el-button><el-dialog :visible.sync="visible" @open="handleOpen" title="Hello world"><div id="hello"><p>Try Element</p></div></el-dialog></div>
</body><!-- import Vue before Element --><script src="https://unpkg.com/vue/dist/vue.js"></script><!-- import JavaScript --><script src="https://unpkg.com/element-ui/lib/index.js"></script><script>var vm = new Vue({el: '#app',data: function() {return { visible: false }},methods: {handleOpen(){console.log("open: "+$("#hello p").html()); // TAG 1}}})</script>
</html>

element ui dialog 组件提供了 open 事件,在 Dialog 打开时执行回调。

官网对 open 的解释如下

Dialog 的内容是懒渲染的,即在第一次被打开之前,传入的默认 slot 不会被渲染到 DOM 上。因此,如果需要执行 DOM 操作,或通过 ref 获取相应组件,请在 open 事件回调中进行。

可是实际使用时,发现并非如此。

在上例 TAG 1 所处的时间点,实际页面如下:

<div id="app"><button type="button" class="el-button l-button--default"><span>Button</span></button> <div class="el-dialog__wrapper" style="display: none;"><div class="el-dialog" style="margin-top: 15vh;"><div class="el-dialog__header"><span class="el-dialog__title">Hello world</span><button type="button" aria-label="Close" class="el-dialog__headerbtn"><i class="el-dialog__close el-icon el-icon-close"></i></button></div><!----><div class="el-dialog__footer"><div>Hello Hello</div></div></div></div>
</div>

可见,这个时候的页面并不完整,是无法通过选择器获取 dom 元素的,那么对 “#hello” dom 元素的所有操作都是无效的。

此时检测到 dialog 组件的状态如下:

vm.visible                  // true
vm.$children[1].visible     // true
vm.$children[1].rendered    // true
vm.$children[1].opened      // false

2 问题分析

el-dialog 组件会监听 visible 的状态,当状态为 true 时,立刻触发 open 事件,但这个时候 el-dialog__body 的内容还没有渲染。因为 Vue 组件通过 $emit 触发的事件并不是异步执行的,而是同步执行。

代码如下:

 watch: {visible: function(e) {var t = this;e ? (this.closed = !1,this.$emit("open"),this.$el.addEventListener("scroll", this.updatePopper),this.$nextTick(function() {t.$refs.dialog.scrollTop = 0}),this.appendToBody && document.body.appendChild(this.$el)) : (this.$el.removeEventListener("scroll", this.updatePopper),this.closed || this.$emit("close"))}}

正如官方文档所说,Dialog 的内容,也就是 el-dialog__body 中的内容是懒加载的!

那么它懒加载的机制是什么呢?

查看 element dialog 组件的代码,会发现:

<div class="el-dialog__body" v-if="rendered"><slot></slot></div>

Vue 中 v-if 指令的特征是,根据表达式的值在 DOM 中生成或移除一个元素,如果 rendered 为 false,那么该 dom 元素会被移除,当 rendered 为 true 时,对应元素的克隆会被重新插入到 DOM 中。 而 v-show 指令则是根据表达式的值来显示或隐藏 HTML 元素,并不会移除 DOM 元素。

v-if 是惰性的,如果初始渲染时条件为假,则什么也不做,在条件第一次变为真时才开始局部编译(编译结果会缓存起来)。

这就是 element dialog-body 懒加载的原理。

3 解决方案

3.1 将元素放在 footer slot 中

dialog 组件中的 footer slot 是实时渲染的,放在其中的 dom 元素可以直接获取:

  <div id="app"><el-button @click="visible = true">Button</el-button><el-dialog :visible.sync="visible" @open="handleOpen" title="Hello world"><div slot="footer"><div id="hello"><p>Try Element</p></div></div></el-dialog></div>

3.2 在 open 事件中延迟执行具体的代码

由于浏览器是单线程执行前端代码,因此可以短暂的交出控制权,让其进行渲染页面,然后再执行具体的任务。

    var vm = new Vue({el: '#app',data: function() {return { visible: false }},methods: {handleOpen(){setTimeout(console.log, 100, "open: "+$("#hello p").html()) // TAG 1}}})

3.3 在 update 回调函数执行相关的逻辑

当 v-if 为 true 时,会重新渲染页面,渲染结束后会触发 update 回调函数,这个时候可以用来执行一些代码。

    var vm = new Vue({el: '#app',data: function() {return { visible: false,see: true,nosee: false}},updated: function(){var dialog = this.$children[1]if(dialog.rendered && this.visible) {console.log("update: " + $("#hello p").html())}}})

需要注意的时,要对 dialog 的状态进行验证,确保代码的执行时机准确无误。

3.4 主动更改 rendered 的值为 true

在 open dialog 之前,先将 rendered 的值改为 true

    var vm = new Vue({el: '#app',data: function() {return { visible: false }},methods: {handleOpen(){console.log("open: "+$("#hello p").html()); // TAG 1}}})vm.$children[1].rendered = true

可能还有更简洁、高效的方式,知道的朋友可以告知一下,相互学习。

【前端框架】Element UI Dialog 组件中执行 DOM 操作异常问题的分析与处理相关推荐

  1. 前端笔记—第15篇js中的DOM操作

    获取事件源 document.getElementById() document.getElementsByClass() document.getElementsByTagName() docume ...

  2. 前端漫漫-Element UI报错:Unknown custom element: <el-menu>

    前端漫漫-Element UI报错:Unknown custom element: 问题描述:编写VUE文件,从Element UI官网复制组件信息的时候,引用了Element UI的html标签,但 ...

  3. 开源的HTML5前端框架Amaze UI发布,推进mobile first前端Web方案

    2014年6月,云适配发布了开源的HTML5前端框架Amaze UI,目前处于内测期.根据Amaze UI的官网介绍,该框架的特点是mobile first,解决Web应用从PC向多屏适配的问题,兼容 ...

  4. element ui table组件扩展关于列表编辑按钮的位置放置

    最近在用vue做项目,主要是用的element ui的组件,在用的过程中发现有部分组件需要扩展,改源码太折腾,成本高,就想着如何节省成本来实现这些需求,由于项目时间紧张,有些实现来也没来得及记录一下, ...

  5. 实战 | Element UI 父子组件传值与事件绑定(正向)

    这是小小的本周的第三篇,本篇将会讲解关于Element UI 父子组件传值与事件绑定. 父子组件传值 新建父组件和子组件 新建父组件 代码如下 <template><div id=& ...

  6. element ui upload组件文件上传一次 后,不论是上传成功之后修改文件再上传还是上传失败重新上传,再次点击上传均无反应。

    问题: Element UI Upload 组件文件上传一次 后,不论是上传成功之后修改文件再上传还是上传失败重新上传,再次点击上传均无反应. 原因: 第一次上传文件后,浏览器还保存着我们已经上传的文 ...

  7. Vue Element UI 表格组件 利用插槽实现按下按钮后获得本行数据(内容)

    Vue Element UI 表格组件 利用插槽实现按下按钮后获得本行数据(内容) 能够解决的问题 需要在表格中添加一个类似修改或编辑的按钮,按下按钮,弹出的窗口需要本行的渲染数据 需要向服务端提交一 ...

  8. Element UI——滚动条组件(ElScrollBar)修改.el-scrollbar__wrap和el-scrollbar__view的CSS属性

    基本概念 el-scrollbar:Element UI隐藏组件. 注意事项: 1.el-scrollbar的父层要有固定高度 2.el-scrollbar的高度要设成100% 3.如果出现横滚动条, ...

  9. 实战 | Element UI 父子组件传值与事件绑定(逆向)

    这是小小本周的第四篇,本篇将会倒过来讲解Element UI 父子组件传值与事件绑定. 父子组件传值 新建父组件和子组件 新建父组件 代码如下 <template><div id=& ...

  10. 响应式滚动图懒加载 element ui el-carousel 组件优化代码

    响应式滚动图懒加载 element ui  el-carousel 组件优化代码 懒加载插件vue-lazyload //main.js import VueLazyload from 'vue-la ...

最新文章

  1. 为什么分布式一定要有一致性方案?
  2. 大数据系统软件国家工程实验室给大家拜年啦!
  3. dataTable的用法
  4. vue 代理设置 访问图片_详解Vue源码之数据的代理访问
  5. C#2.0泛型中的变化: default 关键字
  6. 【解决方案】jquery live的change事件在IE下失效
  7. Linux内核学习笔记(2)-- 父进程和子进程及它们的访问方法
  8. extjs初学者教程
  9. 最新苹果开发者账号添加设备UDID
  10. 农业统计分析系列2-试验设计
  11. 程序员们的那些神表情,有木有击中你^_^
  12. R语言画个中国地图使用shp文件
  13. CSGO手套武器箱直接卖还是开了再卖?
  14. IntelliJ IDEA注释字体形式修改
  15. 免费UI色彩搭配素材资源|色卡帮你找准搭配技巧
  16. Rman配置DataGuard using Backup-based duplication with a target connection with filesystem
  17. 能帮你找到网页设计灵感的16个网站-沪江UI团队资料翻译组
  18. element组件---Form
  19. 医疗器械系统软件转产方案
  20. 史上最全的Android面试题集锦

热门文章

  1. fbp是什么岗位_BP是什么职位?
  2. CNC:CNC计算机数控系统技术之数控仿真宏程序代码讲解、案例应用集合之详细攻略
  3. java虚拟机中如何判断对象已经可以garbage collected
  4. xdoj-81-字符串查找
  5. 1062 最简分数 (20 分)
  6. transformer中的位置嵌入
  7. 荣耀手表magicwatch2鸿蒙,荣耀手表2 NFC门禁卡功能正式上线:再不怕忘带钥匙
  8. 将分子SMILES生成DGLGraph
  9. WVS与Arachni漏扫工具对比实验
  10. 企业微信群:机器人实现定时提醒功能