ec4aa78f54098690a6325be3afead1c359064c3318dd19821bb189f5582a2e3c6b91c72e134e2215271d931a1e5a22af8ead6e411defe4a2fd12a534cd2a10 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. <script>
  2. import ElCheckbox from 'element-ui/packages/checkbox';
  3. import ElRadio from 'element-ui/packages/radio';
  4. import { isEqual } from 'element-ui/src/utils/util';
  5. const stopPropagation = e => e.stopPropagation();
  6. export default {
  7. inject: ['panel'],
  8. components: {
  9. ElCheckbox,
  10. ElRadio
  11. },
  12. props: {
  13. node: {
  14. required: true
  15. },
  16. nodeId: String
  17. },
  18. computed: {
  19. config() {
  20. return this.panel.config;
  21. },
  22. isLeaf() {
  23. return this.node.isLeaf;
  24. },
  25. isDisabled() {
  26. return this.node.isDisabled;
  27. },
  28. checkedValue() {
  29. return this.panel.checkedValue;
  30. },
  31. isChecked() {
  32. return this.node.isSameNode(this.checkedValue);
  33. },
  34. inActivePath() {
  35. return this.isInPath(this.panel.activePath);
  36. },
  37. inCheckedPath() {
  38. if (!this.config.checkStrictly) return false;
  39. return this.panel.checkedNodePaths
  40. .some(checkedPath => this.isInPath(checkedPath));
  41. },
  42. value() {
  43. return this.node.getValueByOption();
  44. }
  45. },
  46. methods: {
  47. handleExpand() {
  48. const { panel, node, isDisabled, config } = this;
  49. const { multiple, checkStrictly } = config;
  50. if (!checkStrictly && isDisabled || node.loading) return;
  51. if (config.lazy && !node.loaded) {
  52. panel.lazyLoad(node, () => {
  53. // do not use cached leaf value here, invoke this.isLeaf to get new value.
  54. const { isLeaf } = this;
  55. if (!isLeaf) this.handleExpand();
  56. if (multiple) {
  57. // if leaf sync checked state, else clear checked state
  58. const checked = isLeaf ? node.checked : false;
  59. this.handleMultiCheckChange(checked);
  60. }
  61. });
  62. } else {
  63. panel.handleExpand(node);
  64. }
  65. },
  66. handleCheckChange() {
  67. const { panel, value, node } = this;
  68. panel.handleCheckChange(value);
  69. panel.handleExpand(node);
  70. },
  71. handleMultiCheckChange(checked) {
  72. this.node.doCheck(checked);
  73. this.panel.calculateMultiCheckedValue();
  74. },
  75. isInPath(pathNodes) {
  76. const { node } = this;
  77. const selectedPathNode = pathNodes[node.level - 1] || {};
  78. return selectedPathNode.uid === node.uid;
  79. },
  80. renderPrefix(h) {
  81. const { isLeaf, isChecked, config } = this;
  82. const { checkStrictly, multiple } = config;
  83. if (multiple) {
  84. return this.renderCheckbox(h);
  85. } else if (checkStrictly) {
  86. return this.renderRadio(h);
  87. } else if (isLeaf && isChecked) {
  88. return this.renderCheckIcon(h);
  89. }
  90. return null;
  91. },
  92. renderPostfix(h) {
  93. const { node, isLeaf } = this;
  94. if (node.loading) {
  95. return this.renderLoadingIcon(h);
  96. } else if (!isLeaf) {
  97. return this.renderExpandIcon(h);
  98. }
  99. return null;
  100. },
  101. renderCheckbox(h) {
  102. const { node, config, isDisabled } = this;
  103. const events = {
  104. on: { change: this.handleMultiCheckChange },
  105. nativeOn: {}
  106. };
  107. if (config.checkStrictly) { // when every node is selectable, click event should not trigger expand event.
  108. events.nativeOn.click = stopPropagation;
  109. }
  110. return (
  111. <el-checkbox
  112. value={ node.checked }
  113. indeterminate={ node.indeterminate }
  114. disabled={ isDisabled }
  115. { ...events }
  116. ></el-checkbox>
  117. );
  118. },
  119. renderRadio(h) {
  120. let { checkedValue, value, isDisabled } = this;
  121. // to keep same reference if value cause radio's checked state is calculated by reference comparision;
  122. if (isEqual(value, checkedValue)) {
  123. value = checkedValue;
  124. }
  125. return (
  126. <el-radio
  127. value={ checkedValue }
  128. label={ value }
  129. disabled={ isDisabled }
  130. onChange={ this.handleCheckChange }
  131. nativeOnClick={ stopPropagation }>
  132. {/* add an empty element to avoid render label */}
  133. <span></span>
  134. </el-radio>
  135. );
  136. },
  137. renderCheckIcon(h) {
  138. return (
  139. <i class="el-icon-check el-cascader-node__prefix"></i>
  140. );
  141. },
  142. renderLoadingIcon(h) {
  143. return (
  144. <i class="el-icon-loading el-cascader-node__postfix"></i>
  145. );
  146. },
  147. renderExpandIcon(h) {
  148. return (
  149. <i class="el-icon-arrow-right el-cascader-node__postfix"></i>
  150. );
  151. },
  152. renderContent(h) {
  153. const { panel, node } = this;
  154. const render = panel.renderLabelFn;
  155. const vnode = render
  156. ? render({ node, data: node.data })
  157. : null;
  158. return (
  159. <span class="el-cascader-node__label">{ vnode || node.label }</span>
  160. );
  161. }
  162. },
  163. render(h) {
  164. const {
  165. inActivePath,
  166. inCheckedPath,
  167. isChecked,
  168. isLeaf,
  169. isDisabled,
  170. config,
  171. nodeId
  172. } = this;
  173. const { expandTrigger, checkStrictly, multiple } = config;
  174. const disabled = !checkStrictly && isDisabled;
  175. const events = { on: {} };
  176. if (expandTrigger === 'click') {
  177. events.on.click = this.handleExpand;
  178. } else {
  179. events.on.mouseenter = e => {
  180. this.handleExpand();
  181. this.$emit('expand', e);
  182. };
  183. events.on.focus = e => {
  184. this.handleExpand();
  185. this.$emit('expand', e);
  186. };
  187. }
  188. if (isLeaf && !isDisabled && !checkStrictly && !multiple) {
  189. events.on.click = this.handleCheckChange;
  190. }
  191. return (
  192. <li
  193. role="menuitem"
  194. id={ nodeId }
  195. aria-expanded={ inActivePath }
  196. tabindex={ disabled ? null : -1 }
  197. class={{
  198. 'el-cascader-node': true,
  199. 'is-selectable': checkStrictly,
  200. 'in-active-path': inActivePath,
  201. 'in-checked-path': inCheckedPath,
  202. 'is-active': isChecked,
  203. 'is-disabled': disabled
  204. }}
  205. {...events}>
  206. { this.renderPrefix(h) }
  207. { this.renderContent(h) }
  208. { this.renderPostfix(h) }
  209. </li>
  210. );
  211. }
  212. };
  213. </script>