123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- <script>
- import ElScrollbar from 'element-ui/packages/scrollbar';
- import CascaderNode from './cascader-node.vue';
- import Locale from 'element-ui/src/mixins/locale';
- import { generateId } from 'element-ui/src/utils/util';
- export default {
- name: 'ElCascaderMenu',
- mixins: [Locale],
- inject: ['panel'],
- components: {
- ElScrollbar,
- CascaderNode
- },
- props: {
- nodes: {
- type: Array,
- required: true
- },
- index: Number
- },
- data() {
- return {
- activeNode: null,
- hoverTimer: null,
- id: generateId()
- };
- },
- computed: {
- isEmpty() {
- return !this.nodes.length;
- },
- menuId() {
- return `cascader-menu-${this.id}-${this.index}`;
- }
- },
- methods: {
- handleExpand(e) {
- this.activeNode = e.target;
- },
- handleMouseMove(e) {
- const { activeNode, hoverTimer } = this;
- const { hoverZone } = this.$refs;
- if (!activeNode || !hoverZone) return;
- if (activeNode.contains(e.target)) {
- clearTimeout(hoverTimer);
- const { left } = this.$el.getBoundingClientRect();
- const startX = e.clientX - left;
- const { offsetWidth, offsetHeight } = this.$el;
- const top = activeNode.offsetTop;
- const bottom = top + activeNode.offsetHeight;
- hoverZone.innerHTML = `
- <path style="pointer-events: auto;" fill="transparent" d="M${startX} ${top} L${offsetWidth} 0 V${top} Z" />
- <path style="pointer-events: auto;" fill="transparent" d="M${startX} ${bottom} L${offsetWidth} ${offsetHeight} V${bottom} Z" />
- `;
- } else if (!hoverTimer) {
- this.hoverTimer = setTimeout(this.clearHoverZone, this.panel.config.hoverThreshold);
- }
- },
- clearHoverZone() {
- const { hoverZone } = this.$refs;
- if (!hoverZone) return;
- hoverZone.innerHTML = '';
- },
- renderEmptyText(h) {
- return (
- <div class="el-cascader-menu__empty-text">{ this.t('el.cascader.noData') }</div>
- );
- },
- renderNodeList(h) {
- const { menuId } = this;
- const { isHoverMenu } = this.panel;
- const events = { on: {} };
- if (isHoverMenu) {
- events.on.expand = this.handleExpand;
- }
- const nodes = this.nodes.map((node, index) => {
- const { hasChildren } = node;
- return (
- <cascader-node
- key={ node.uid }
- node={ node }
- node-id={ `${menuId}-${index}` }
- aria-haspopup={ hasChildren }
- aria-owns = { hasChildren ? menuId : null }
- { ...events }></cascader-node>
- );
- });
- return [
- ...nodes,
- isHoverMenu ? <svg ref='hoverZone' class='el-cascader-menu__hover-zone'></svg> : null
- ];
- }
- },
- render(h) {
- const { isEmpty, menuId } = this;
- const events = { nativeOn: {} };
- // optimize hover to expand experience (#8010)
- if (this.panel.isHoverMenu) {
- events.nativeOn.mousemove = this.handleMouseMove;
- // events.nativeOn.mouseleave = this.clearHoverZone;
- }
- return (
- <el-scrollbar
- tag="ul"
- role="menu"
- id={ menuId }
- class="el-cascader-menu"
- wrap-class="el-cascader-menu__wrap"
- view-class={{
- 'el-cascader-menu__list': true,
- 'is-empty': isEmpty
- }}
- { ...events }>
- { isEmpty ? this.renderEmptyText(h) : this.renderNodeList(h) }
- </el-scrollbar>
- );
- }
- };
- </script>
|