草庐IT

el-table溢出隐藏 鼠标移入显示tooltip逻辑

霂沁 2023-04-04 原文

el-table溢出隐藏 鼠标移入显示tooltip 逻辑

el-table

文件 element-ui/packages/table/src/table-body.js 截取部分代码

export default {
  render(h) {
    return (
      <table>
        <tbody>
          {/* 表格内容 ... */}
          {/* 一个表格 只渲染一个 tooltip */}
          <el-tooltip effect={this.table.tooltipEffect} placement="top" ref="tooltip" content={this.tooltipContent}></el-tooltip>
        </tbody>
      </table>
    );
  },
  created() {
    this.activateTooltip = debounce(50, tooltip => tooltip.handleShowPopper());
  },
  methods: {
    handleCellMouseEnter(event, row) {  // 鼠标移入表格项 触发事件
      const table = this.table;
      const cell = getCell(event);

      if (cell) {
        const column = getColumnByCell(table, cell);
        const hoverState = table.hoverState = { cell, column, row };
        table.$emit('cell-mouse-enter', hoverState.row, hoverState.column, hoverState.cell, event);
      }
      // 判断是否text-overflow, 如果是就显示tooltip
      const cellChild = event.target.querySelector('.cell');
      if (!(hasClass(cellChild, 'el-tooltip') && cellChild.childNodes.length)) {
        return;
      }
      // use range width instead of scrollWidth to determine whether the text is overflowing
      // to address a potential FireFox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1074543#c3
      const range = document.createRange();
      range.setStart(cellChild, 0);
      range.setEnd(cellChild, cellChild.childNodes.length);
      const rangeWidth = range.getBoundingClientRect().width;
      const padding = (parseInt(getStyle(cellChild, 'paddingLeft'), 10) || 0) +
        (parseInt(getStyle(cellChild, 'paddingRight'), 10) || 0);
      if ((rangeWidth + padding > cellChild.offsetWidth || cellChild.scrollWidth > cellChild.offsetWidth) && this.$refs.tooltip) {
        // 1. 判断: 如果宽度溢出
        const tooltip = this.$refs.tooltip;
        // TODO 会引起整个 Table 的重新渲染,需要优化
        this.tooltipContent = cell.innerText || cell.textContent; // 2. 表格项内容 赋值给 tooltip显示
        tooltip.referenceElm = cell;  // 3. 替换referenceElm, tooltip通过Popper.js 计算显示的tooltip和referenceElm的相对位置
        tooltip.$refs.popper && (tooltip.$refs.popper.style.display = 'none');
        tooltip.doDestroy();	// 取消tooltip上一系列绑定事件
        tooltip.setExpectedState(true);
        this.activateTooltip(tooltip);  // 4. 显示tooltip
      }
    },
    handleCellMouseLeave(event) { // 鼠标溢出表格项 触发事件
      const tooltip = this.$refs.tooltip;
      if (tooltip) {
        tooltip.setExpectedState(false);
        tooltip.handleClosePopper();  // 隐藏tooltip
      }
      const cell = getCell(event);
      if (!cell) return;

      const oldHoverState = this.table.hoverState || {};
      this.table.$emit('cell-mouse-leave', oldHoverState.row, oldHoverState.column, oldHoverState.cell, event);
    },
  }
}

记录点

  1. 鼠标事件
    mouseenter/mouseleave(新),mouseover/mouseout(旧)
    新的鼠标移入移出事件,去掉了冒泡和捕获的特性
    • mouseenter:鼠标第一次移动到元素区域时触发 (新)
    • mouseleave:移出时触发(新)
    • mousemove:在元素上移动时触发(一直触发)
    • mouseover:鼠标移动到元素上时触发(旧)
    • mouseout:从元素上移开时触发(旧)
  2. 步骤
    • el-tooltiptbody的子节点,一个表格,只渲染一个 el-tooltip
    • 监听鼠标移入事件 mouseenter,判断表格项内容是否溢出
    • 如果溢出
      • 表格项内容赋值给 tooltipContent 显示隐藏内容
      • 替换referenceElm, tooltip通过 Popper.js 计算显示的 tooltipreferenceElm 的相对位置
      • 显示 tooltip
    • 监听鼠标移开事件 mouseleave,隐藏 tooltip

el-tooltip

文件 element-ui/packages/tooltip/src/main.js 截取部分代码

const PopperJS = require('element-ui/src/utils/popper.js');
export default {
  beforeCreate() {
    this.popperVM = new Vue({
      data: { node: '' },
      render(h) {
        return this.node;
      }
    }).$mount();
    this.debounceClose = debounce(200, () => this.handleClosePopper());
  },
  render(h) {
    if (this.popperVM) {
      this.popperVM.node = (
        <transition
          name={ this.transition }
          onAfterLeave={ this.doDestroy }>
          <div
            onMouseleave={ () => { this.setExpectedState(false); this.debounceClose(); } }
            onMouseenter= { () => { this.setExpectedState(true); } }
            ref="popper"
            role="tooltip"
            id={this.tooltipId}
            aria-hidden={ (this.disabled || !this.showPopper) ? 'true' : 'false' }
            v-show={!this.disabled && this.showPopper}
            class={
              ['el-tooltip__popper', 'is-' + this.effect, this.popperClass]
            }>
            {/* 具名插槽 content 渲染在tooltip */}
            { this.$slots.content || this.content }
          </div>
        </transition>);
    }

    const firstElement = this.getFirstElement();  
    if (!firstElement) return null;

    const data = firstElement.data = firstElement.data || {};
    data.staticClass = this.addTooltipClass(data.staticClass);

    return firstElement;  // 找到默认插槽 default 显示在组件位置
  },
  mounted() {
    this.referenceElm = this.$el;
    // 给 referenceElm 绑定一系列事件, 包括: mouseenter mouseleave
    // ...
    
    if (this.value && this.popperVM) {
      this.popperVM.$nextTick(() => {
        if (this.value) {
          this.updatePopper();
        }
      });
    }
  },
  methods: {
    updatePopper() {
      const popperJS = this.popperJS;
      if (popperJS) {
        popperJS.update();
        if (popperJS._popper) {
          popperJS._popper.style.zIndex = PopupManager.nextZIndex();
        }
      } else {
        this.createPopper();
      }
    },
    createPopper() { // 省略...只剩下需要的逻辑
      let reference = this.referenceElm = this.referenceElm || this.reference || this.$refs.reference;
      const popper = this.popperElm = this.popperElm || this.popper || this.$refs.popper; // 提示信息ref 对应的DOM
      const options = this.popperOptions;

      if (!popper || !reference) return;
      if (this.appendToBody) document.body.appendChild(this.popperElm); // 渲染在body节点下
      /**
       * reference: 默认插槽/鼠标移入移出显示tooltip相对的元素
       * popper: 提示信息ref 对应的DOM (tooltip)
       * option: 一些配置
       */
      this.popperJS = new PopperJS(reference, popper, options);
      // ...
    }
  }
}

记录点:

  1. render
    1. 找到默认插槽 default 显示在组件位置
    2. 提示信息:transition + 具名插槽 content,鼠标移入referenceElm,显示提示信息
  2. mounted:给 referenceElm 绑定一系列事件, 包括: mouseentermouseleave,调用 updatePopper
  3. 调用 createPopper
    1. 通过 Popper.js 计算显示的 提示信息 和 referenceElm 的相对位置
    2. 关键代码:this.popperJS = new PopperJS(reference, popper, options);
      • reference: 默认插槽/referenceElm,鼠标移入移出显示 提示信息 相对的元素
      • popper: 提示信息ref 对应的DOM (tooltip)
      • option: 一些配置

有关el-table溢出隐藏 鼠标移入显示tooltip逻辑的更多相关文章

  1. ruby-on-rails - Rails 编辑表单不显示嵌套项 - 2

    我得到了一个包含嵌套链接的表单。编辑时链接字段为空的问题。这是我的表格:Editingkategori{:action=>'update',:id=>@konkurrancer.id})do|f|%>'Trackingurl',:style=>'width:500;'%>'Editkonkurrence'%>|我的konkurrencer模型:has_one:link我的链接模型:classLink我的konkurrancer编辑操作:defedit@konkurrancer=Konkurrancer.find(params[:id])@konkurrancer.link_attrib

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby-on-rails - 使用 Sublime Text 3 突出显示 HTML 背景语法中的 ERB? - 2

    所以我在关注Railscast,我注意到在html.erb文件中,ruby代码有一个微弱的背景高亮效果,以区别于其他代码HTML文档。我知道Ryan使用TextMate。我正在使用SublimeText3。我怎样才能达到同样的效果?谢谢! 最佳答案 为SublimeText安装ERB包。假设您安装了SublimeText包管理器*,只需点击cmd+shift+P即可获得命令菜单,然后键入installpackage并选择PackageControl:InstallPackage获取包管理器菜单。在该菜单中,键入ERB并在看到包时选择

  4. ruby-on-rails - link_to 不显示任何 rails - 2

    我试图在索引页中创建一个超链接,但它没有显示,也没有给出任何错误。这是我的index.html.erb代码。ListingarticlesTitleTextssss我检查了我的路线,我认为它们也没有问题。PrefixVerbURIPatternController#Actionwelcome_indexGET/welcome/index(.:format)welcome#indexarticlesGET/articles(.:format)articles#indexPOST/articles(.:format)articles#createnew_articleGET/article

  5. ruby-on-rails - 如何在 Rails View 上显示错误消息? - 2

    我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c

  6. ruby-on-rails - Prawn PDF : I need to generate nested tables - 2

    我需要一个表,其中行实际上是2行表,一个嵌套表是..我怎样才能在Prawn中做到这一点?也许我需要延期..但哪一个? 最佳答案 现在支持子表:Prawn::Document.generate("subtable.pdf")do|pdf|subtable=pdf.make_table([["sub"],["table"]])pdf.table([[subtable,"original"]])end 关于ruby-on-rails-PrawnPDF:Ineedtogeneratenested

  7. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  8. ruby-on-rails - 复数 for fields_for has_many 关联未显示在 View 中 - 2

    目前,Itembelongs_toCompany和has_manyItemVariants。我正在尝试使用嵌套的fields_for通过Item表单添加ItemVariant字段,但是使用:item_variants不显示该表单。只有当我使用单数时才会显示。我检查了我的关联,它们似乎是正确的,这可能与嵌套在公司下的项目有关,还是我遗漏了其他东西?提前致谢。注意:下面的代码片段中省略了不相关的代码。编辑:不知道这是否相关,但我正在使用CanCan进行身份验证。routes.rbresources:companiesdoresources:itemsenditem.rbclassItemi

  9. ruby-on-rails - 在 Flash 警报 Rails 3 中显示错误消息 - 2

    如果我在模型中设置验证消息validates:name,:presence=>{:message=>'Thenamecantbeblank.'}我如何让该消息显示在闪光警报中,这是我迄今为止尝试过的方法defcreate@message=Message.new(params[:message])if@message.valid?ContactMailer.send_mail(@message).deliverredirect_to(root_path,:notice=>"Thanksforyourmessage,Iwillbeintouchsoon")elseflash[:error]

  10. ruby-on-rails - Rails 4 WYSIWYG Bootsy 不显示格式 - 2

    我刚刚按照thebootsygempage上的安装说明进行操作在我保存并查看帖子内容之前,一切看起来都不错。这是输出在View中的样子:HeaderSubhead:似乎没有呈现任何html格式,因为它被引号或类似的东西转义了-其他人有这个问题吗?我没有在github页面或SO上看到任何问题来指出我正确的方向。除了遵循gem安装说明之外,我还没有做任何事情,但也许我错过了什么或者只是犯了一个愚蠢的错误。如果你还有什么想知道的,请尽管问。干杯 最佳答案 你需要有这样的东西,转义html: 关

随机推荐