| <template> | 
|   <div | 
|     class="el-tree-node" | 
|     @click.stop="handleClick" | 
|     @contextmenu="($event) => this.handleContextMenu($event)" | 
|     v-show="node.visible" | 
|     :class="{ | 
|       'is-expanded': expanded, | 
|       'is-current': node.isCurrent, | 
|       'is-hidden': !node.visible, | 
|       'is-focusable': !node.disabled, | 
|       'is-checked': !node.disabled && node.checked | 
|     }" | 
|     role="treeitem" | 
|     tabindex="-1" | 
|     :aria-expanded="expanded" | 
|     :aria-disabled="node.disabled" | 
|     :aria-checked="node.checked" | 
|     :draggable="tree.draggable" | 
|     @dragstart.stop="handleDragStart" | 
|     @dragover.stop="handleDragOver" | 
|     @dragend.stop="handleDragEnd" | 
|     @drop.stop="handleDrop" | 
|     ref="node" | 
|   > | 
|     <div class="el-tree-node__content" | 
|       :style="{ 'padding-left': (node.level - 1) * tree.indent + 'px' }"> | 
|       <span | 
|         @click.stop="handleExpandIconClick" | 
|         :class="[ | 
|           { 'is-leaf': node.isLeaf, expanded: !node.isLeaf && expanded }, | 
|           'el-tree-node__expand-icon', | 
|           tree.iconClass ? tree.iconClass : 'el-icon-caret-right' | 
|         ]" | 
|       > | 
|       </span> | 
|       <el-checkbox | 
|         v-if="showCheckbox" | 
|         v-model="node.checked" | 
|         :indeterminate="node.indeterminate" | 
|         :disabled="!!node.disabled" | 
|         @click.native.stop | 
|         @change="handleCheckChange" | 
|       > | 
|       </el-checkbox> | 
|       <span | 
|         v-if="node.loading" | 
|         class="el-tree-node__loading-icon el-icon-loading"> | 
|       </span> | 
|       <node-content :node="node"></node-content> | 
|     </div> | 
|     <el-collapse-transition> | 
|       <div | 
|         class="el-tree-node__children" | 
|         v-if="!renderAfterExpand || childNodeRendered" | 
|         v-show="expanded" | 
|         role="group" | 
|         :aria-expanded="expanded" | 
|       > | 
|         <el-tree-node | 
|           :render-content="renderContent" | 
|           v-for="child in node.childNodes" | 
|           :render-after-expand="renderAfterExpand" | 
|           :show-checkbox="showCheckbox" | 
|           :key="getNodeKey(child)" | 
|           :node="child" | 
|           @node-expand="handleChildNodeExpand"> | 
|         </el-tree-node> | 
|       </div> | 
|     </el-collapse-transition> | 
|   </div> | 
| </template> | 
|   | 
| <script type="text/jsx"> | 
|   import ElCollapseTransition from 'element-ui/src/transitions/collapse-transition'; | 
|   import ElCheckbox from 'element-ui/packages/checkbox'; | 
|   import emitter from 'element-ui/src/mixins/emitter'; | 
|   import { getNodeKey } from './model/util'; | 
|   | 
|   export default { | 
|     name: 'ElTreeNode', | 
|   | 
|     componentName: 'ElTreeNode', | 
|   | 
|     mixins: [emitter], | 
|   | 
|     props: { | 
|       node: { | 
|         default() { | 
|           return {}; | 
|         } | 
|       }, | 
|       props: {}, | 
|       renderContent: Function, | 
|       renderAfterExpand: { | 
|         type: Boolean, | 
|         default: true | 
|       }, | 
|       showCheckbox: { | 
|         type: Boolean, | 
|         default: false | 
|       } | 
|     }, | 
|   | 
|     components: { | 
|       ElCollapseTransition, | 
|       ElCheckbox, | 
|       NodeContent: { | 
|         props: { | 
|           node: { | 
|             required: true | 
|           } | 
|         }, | 
|         render(h) { | 
|           const parent = this.$parent; | 
|           const tree = parent.tree; | 
|           const node = this.node; | 
|           const { data, store } = node; | 
|           return ( | 
|             parent.renderContent | 
|               ? parent.renderContent.call(parent._renderProxy, h, { _self: tree.$vnode.context, node, data, store }) | 
|               : tree.$scopedSlots.default | 
|                 ? tree.$scopedSlots.default({ node, data }) | 
|                 : <span class="el-tree-node__label">{ node.label }</span> | 
|           ); | 
|         } | 
|       } | 
|     }, | 
|   | 
|     data() { | 
|       return { | 
|         tree: null, | 
|         expanded: false, | 
|         childNodeRendered: false, | 
|         oldChecked: null, | 
|         oldIndeterminate: null | 
|       }; | 
|     }, | 
|   | 
|     watch: { | 
|       'node.indeterminate'(val) { | 
|         this.handleSelectChange(this.node.checked, val); | 
|       }, | 
|   | 
|       'node.checked'(val) { | 
|         this.handleSelectChange(val, this.node.indeterminate); | 
|       }, | 
|   | 
|       'node.expanded'(val) { | 
|         this.$nextTick(() => this.expanded = val); | 
|         if (val) { | 
|           this.childNodeRendered = true; | 
|         } | 
|       } | 
|     }, | 
|   | 
|     methods: { | 
|       getNodeKey(node) { | 
|         return getNodeKey(this.tree.nodeKey, node.data); | 
|       }, | 
|   | 
|       handleSelectChange(checked, indeterminate) { | 
|         if (this.oldChecked !== checked && this.oldIndeterminate !== indeterminate) { | 
|           this.tree.$emit('check-change', this.node.data, checked, indeterminate); | 
|         } | 
|         this.oldChecked = checked; | 
|         this.indeterminate = indeterminate; | 
|       }, | 
|   | 
|       handleClick() { | 
|         const store = this.tree.store; | 
|         store.setCurrentNode(this.node); | 
|         this.tree.$emit('current-change', store.currentNode ? store.currentNode.data : null, store.currentNode); | 
|         this.tree.currentNode = this; | 
|         if (this.tree.expandOnClickNode) { | 
|           this.handleExpandIconClick(); | 
|         } | 
|         if (this.tree.checkOnClickNode && !this.node.disabled) { | 
|           this.handleCheckChange(null, { | 
|             target: { checked: !this.node.checked } | 
|           }); | 
|         } | 
|         this.tree.$emit('node-click', this.node.data, this.node, this); | 
|       }, | 
|   | 
|       handleContextMenu(event) { | 
|         if (this.tree._events['node-contextmenu'] && this.tree._events['node-contextmenu'].length > 0) { | 
|           event.stopPropagation(); | 
|           event.preventDefault(); | 
|         } | 
|         this.tree.$emit('node-contextmenu', event, this.node.data, this.node, this); | 
|       }, | 
|   | 
|       handleExpandIconClick() { | 
|         if (this.node.isLeaf) return; | 
|         if (this.expanded) { | 
|           this.tree.$emit('node-collapse', this.node.data, this.node, this); | 
|           this.node.collapse(); | 
|         } else { | 
|           this.node.expand(); | 
|           this.$emit('node-expand', this.node.data, this.node, this); | 
|         } | 
|       }, | 
|   | 
|       handleCheckChange(value, ev) { | 
|         this.node.setChecked(ev.target.checked, !this.tree.checkStrictly); | 
|         this.$nextTick(() => { | 
|           const store = this.tree.store; | 
|           this.tree.$emit('check', this.node.data, { | 
|             checkedNodes: store.getCheckedNodes(), | 
|             checkedKeys: store.getCheckedKeys(), | 
|             halfCheckedNodes: store.getHalfCheckedNodes(), | 
|             halfCheckedKeys: store.getHalfCheckedKeys(), | 
|           }); | 
|         }); | 
|       }, | 
|   | 
|       handleChildNodeExpand(nodeData, node, instance) { | 
|         this.broadcast('ElTreeNode', 'tree-node-expand', node); | 
|         this.tree.$emit('node-expand', nodeData, node, instance); | 
|       }, | 
|   | 
|       handleDragStart(event) { | 
|         if (!this.tree.draggable) return; | 
|         this.tree.$emit('tree-node-drag-start', event, this); | 
|       }, | 
|   | 
|       handleDragOver(event) { | 
|         if (!this.tree.draggable) return; | 
|         this.tree.$emit('tree-node-drag-over', event, this); | 
|         event.preventDefault(); | 
|       }, | 
|   | 
|       handleDrop(event) { | 
|         event.preventDefault(); | 
|       }, | 
|   | 
|       handleDragEnd(event) { | 
|         if (!this.tree.draggable) return; | 
|         this.tree.$emit('tree-node-drag-end', event, this); | 
|       } | 
|     }, | 
|   | 
|     created() { | 
|       const parent = this.$parent; | 
|   | 
|       if (parent.isTree) { | 
|         this.tree = parent; | 
|       } else { | 
|         this.tree = parent.tree; | 
|       } | 
|   | 
|       const tree = this.tree; | 
|       if (!tree) { | 
|         console.warn('Can not find node\'s tree.'); | 
|       } | 
|   | 
|       const props = tree.props || {}; | 
|       const childrenKey = props['children'] || 'children'; | 
|   | 
|       this.$watch(`node.data.${childrenKey}`, () => { | 
|         this.node.updateChildren(); | 
|       }); | 
|   | 
|       if (this.node.expanded) { | 
|         this.expanded = true; | 
|         this.childNodeRendered = true; | 
|       } | 
|   | 
|       if(this.tree.accordion) { | 
|         this.$on('tree-node-expand', node => { | 
|           if(this.node !== node) { | 
|             this.node.collapse(); | 
|           } | 
|         }); | 
|       } | 
|     } | 
|   }; | 
| </script> |