Commit e81207a2a24ef76d5298994ddd797a6a4c9192c1

Authored by 梁灏
1 parent a861963b

update Tree

update Tree
src/components/tree/tree-node.vue deleted
1   -<template>
2   -
3   -</template>
4   -<script>
5   - export default {
6   - props: {},
7   - data () {
8   - return {};
9   - },
10   - computed: {},
11   - methods: {}
12   - };
13   -</script>
14 0 \ No newline at end of file
src/components/tree/tree.vue
1 1 <template>
2   -
  2 + <ul :class="classes">
  3 + <li v-for="item in data" :class="itemCls(item)">
  4 + <span :class="arrowCls(item)" @click="setExpand(item.disabled, $index)"></span>
  5 + <span v-if="showCheckbox" :class="checkboxCls(item)" @click="setCheck(item.disabled||item.disableCheckbox,$index)">
  6 + <span :class="[prefixCls + '-checkbox-inner']"></span>
  7 + </span>
  8 + <a :class="titleCls(item)" @click="setSelect(item.disabled, $index)">
  9 + <span :class="[prefixCls + '-title']" v-html="item.title"></span>
  10 + </a>
  11 + <tree
  12 + v-if="!item.isLeaf"
  13 + v-show="item.expand"
  14 + :class="expandCls(item)"
  15 + :data.sync="item.node"
  16 + :key="this.key+'.'+$index"
  17 + :multiple="multiple"
  18 + :show-checkbox="showCheckbox"
  19 + transition="slide-up"></tree>
  20 + </li>
  21 + </ul>
3 22 </template>
4 23 <script>
  24 + import { t } from '../../locale';
  25 +
  26 + const prefixCls = 'ivu-tree';
  27 +
5 28 export default {
6   - props: {},
  29 + name: 'tree',
  30 + props: {
  31 + data: {
  32 + type: Array,
  33 + default () {
  34 + return [];
  35 + }
  36 + },
  37 + key: {
  38 + type: String,
  39 + default: '0'
  40 + },
  41 + multiple: {
  42 + type: Boolean,
  43 + default: false
  44 + },
  45 + showCheckbox: {
  46 + type: Boolean,
  47 + default: false
  48 + },
  49 + onSelect: {
  50 + type: Function,
  51 + default () {
  52 + return {};
  53 + }
  54 + },
  55 + onCheck: {
  56 + type: Function,
  57 + default () {
  58 + return {};
  59 + }
  60 + },
  61 + emptyText: {
  62 + type: String,
  63 + default () {
  64 + return t('i.tree.emptyText');
  65 + }
  66 + }
  67 + },
7 68 data () {
8   - return {};
  69 + return {
  70 + prefixCls: prefixCls
  71 + };
9 72 },
10   - computed: {},
11   - methods: {}
  73 + computed: {
  74 + classes () {
  75 + if (this.key === '0') {
  76 + return this.prefixCls;
  77 + } else {
  78 + return `${this.prefixCls}-child-tree`;
  79 + }
  80 + }
  81 + },
  82 + watch: {
  83 + data(){
  84 + if (this.key === '0') {
  85 + this.setKey();
  86 + this.preHandle();
  87 + }
  88 + }
  89 + },
  90 + methods: {
  91 + itemCls (item) {
  92 + return [
  93 + {
  94 + [`${prefixCls}-item-disabled`]: item.disabled
  95 + }
  96 + ];
  97 + },
  98 + arrowCls (item) {
  99 + return [
  100 + `${this.prefixCls}-switcher`,
  101 + {
  102 + [`${this.prefixCls}-switcher-disabled`]: item.disabled,
  103 + [`${this.prefixCls}-noline_close`]: !item.expand && !item.isLeaf,
  104 + [`${this.prefixCls}-noline_open`]: item.expand && !item.isLeaf,
  105 + [`${this.prefixCls}-switcher-noop`]: item.isLeaf
  106 + }
  107 + ];
  108 + },
  109 + checkboxCls (item) {
  110 + return [
  111 + `${this.prefixCls}-checkbox`,
  112 + {
  113 + [`${this.prefixCls}-checkbox-disabled`]: item.disabled || item.disableCheckbox,
  114 + [`${this.prefixCls}-checkbox-checked`]: item.checked && item.childrenCheckedStatus == 2,
  115 + [`${this.prefixCls}-checkbox-indeterminate`]: item.checked && item.childrenCheckedStatus == 1
  116 + }
  117 + ];
  118 + },
  119 + titleCls (item) {
  120 + return [
  121 + {
  122 + [`${this.prefixCls}-node-selected`]: item.selected
  123 + }
  124 + ];
  125 + },
  126 + expandCls (item) {
  127 + return [
  128 + {
  129 + [`${this.prefixCls}-child-tree-open`]: item.expand
  130 + }
  131 + ];
  132 + },
  133 + setKey () {
  134 + for (let i = 0; i < this.data.length; i++) {
  135 + this.data[i].key = `${this.key}.${i}`;
  136 + }
  137 + },
  138 + preHandle(){
  139 + for (let [i,item] of this.data.entries()) {
  140 + if (!item.node || !item.node.length) {
  141 + this.$set(`data[${i}].isLeaf`, true);
  142 + this.$set(`data[${i}].childrenCheckedStatus`, 2);
  143 + continue;
  144 + }
  145 + if (item.checked && !item.childrenCheckedStatus) {
  146 + this.$set(`data[${i}].childrenCheckedStatus`, 2);
  147 + this.$broadcast('parentChecked', true, `${this.key}.${i}`);
  148 + } else {
  149 + let status = this.getChildrenCheckedStatus(item.node);
  150 + this.$set(`data[${i}].childrenCheckedStatus`, status);
  151 + if (status !== 0) this.$set(`data[${i}].checked`, true);
  152 + }
  153 + }
  154 + },
  155 + setExpand(disabled, index){
  156 + if (!disabled) {
  157 + this.$set(`data[${index}].expand`, !this.data[index].expand);
  158 + }
  159 + },
  160 + setSelect(disabled, index){
  161 + if (!disabled) {
  162 + const selected = !this.data[index].selected;
  163 + if (this.multiple || !selected) {
  164 + this.$set(`data[${index}].selected`, selected);
  165 + } else {
  166 + for (let i = 0; i < this.data.length; i++) {
  167 + if (i == index) {
  168 + this.$set(`data[${i}].selected`, true);
  169 + } else {
  170 + this.$set(`data[${i}].selected`, false);
  171 + }
  172 + }
  173 + }
  174 + this.$dispatch('nodeSelected', this, selected);
  175 + }
  176 + },
  177 + setCheck(disabled, index){
  178 + if (disabled) return;
  179 + const checked = !this.data[index].checked;
  180 + this.$set(`data[${index}].checked`, checked);
  181 + this.$set(`data[${index}].childrenCheckedStatus`, checked ? 2 : 0);
  182 + this.$dispatch('childChecked', this, this.key);
  183 + this.$broadcast('parentChecked', checked, `${this.key}.${index}`);
  184 + },
  185 + getNodes(data, opt){
  186 + data = data || this.data;
  187 + let res = [];
  188 + for (let node of data) {
  189 + let tmp = true;
  190 + for (let [key, value] of Object.entries(opt)) {
  191 + if (node[key] != value) {
  192 + tmp = false;
  193 + break;
  194 + }
  195 + }
  196 + if (tmp) {
  197 + res.push(node);
  198 + }
  199 + if (node.node && node.node.length) {
  200 + res = res.concat(this.getNodes(node.node, opt));
  201 + }
  202 + }
  203 + return res;
  204 + },
  205 + getSelectedNodes(){
  206 + return this.getNodes(this.data, {selected: true});
  207 + },
  208 + getCheckedNodes(){
  209 + return this.getNodes(this.data, {checked: true, childrenCheckedStatus: 2});
  210 + },
  211 + getChildrenCheckedStatus(children){
  212 + let checkNum = 0, child_childrenAllChecked = true;
  213 + for (let child of children) {
  214 + if (child.checked) {
  215 + checkNum++;
  216 + }
  217 + if (child.childrenCheckedStatus !== 2) {
  218 + child_childrenAllChecked = false;
  219 + }
  220 + }
  221 + // select all
  222 + if (checkNum == children.length) {
  223 + return child_childrenAllChecked ? 2 : 1;
  224 + // select some
  225 + } else if (checkNum > 0) {
  226 + return 1;
  227 + } else {
  228 + return 0;
  229 + }
  230 + }
  231 + },
  232 + ready(){
  233 + this.setKey();
  234 + this.preHandle();
  235 +
  236 + this.$on('nodeSelected', (ori, selected) => {
  237 + if (this.key !== '0') return true;
  238 + if (!this.multiple && selected) {
  239 + if (this !== ori) {
  240 + for (let i = 0; i < this.data.length; i++) {
  241 + this.$set(`data[${i}].selected`, false);
  242 + }
  243 + }
  244 + this.$broadcast('cancelSelected', ori);
  245 + }
  246 + if (this.onSelect) {
  247 + this.$nextTick(() => {
  248 + this.onSelect(this.getSelectedNodes());
  249 + });
  250 + }
  251 + });
  252 + this.$on('cancelSelected', ori => {
  253 + this.$broadcast('cancelSelected', ori);
  254 + if (this !== ori) {
  255 + for (let i = 0; i < this.data.length; i++) {
  256 + this.$set(`data[${i}].selected`, false);
  257 + }
  258 + }
  259 + });
  260 + this.$on('parentChecked', (status, key) => {
  261 + if (this.key == key || this.key.startsWith(key + '.')) {
  262 + for (let i = 0; i < this.data.length; i++) {
  263 + this.$set(`data[${i}].checked`, status);
  264 + this.$set(`data[${i}].childrenCheckedStatus`, status ? 2 : 0);
  265 + }
  266 + this.$broadcast('parentChecked', status, key);
  267 + }
  268 + });
  269 + this.$on('childChecked', (ori, key) => {
  270 + if (this.key === '0' && this.onCheck) {
  271 + this.$nextTick(() => {
  272 + this.onCheck(this.getCheckedNodes());
  273 + });
  274 + }
  275 + if (this === ori) return;
  276 + for (let [i,item] of this.data.entries()) {
  277 + if (this.key + '.' + i == key) {
  278 + let temp = this.getChildrenCheckedStatus(item.node);
  279 + if (temp != item.childrenCheckedStatus) {
  280 + this.$set(`data[${i}].checked`, !!temp);
  281 + this.$set(`data[${i}].childrenCheckedStatus`, temp);
  282 + if (this.key !== '0') this.$dispatch('childChecked', this, this.key);
  283 + }
  284 + }
  285 + }
  286 + });
  287 + }
12 288 };
13 289 </script>
14 290 \ No newline at end of file
... ...
src/locale/lang/en-US.js
... ... @@ -87,6 +87,9 @@ export default {
87 87 rate: {
88 88 star: 'Star',
89 89 stars: 'Stars'
  90 + },
  91 + tree: {
  92 + emptyText: 'No Data'
90 93 }
91 94 }
92 95 };
93 96 \ No newline at end of file
... ...
src/locale/lang/zh-CN.js
... ... @@ -87,6 +87,9 @@ export default {
87 87 rate: {
88 88 star: '星',
89 89 stars: '星'
  90 + },
  91 + tree: {
  92 + emptyText: '暂无数据'
90 93 }
91 94 }
92 95 };
93 96 \ No newline at end of file
... ...
src/locale/lang/zh-TW.js
... ... @@ -87,6 +87,9 @@ export default {
87 87 rate: {
88 88 star: '星',
89 89 stars: '星'
  90 + },
  91 + tree: {
  92 + emptyText: '暫無數據'
90 93 }
91 94 }
92 95 };
93 96 \ No newline at end of file
... ...
src/styles/components/tree.less
1 1 @tree-prefix-cls: ~"@{css-prefix}tree";
2 2  
3 3 .@{tree-prefix-cls} {
4   -
  4 + margin: 0;
  5 + padding: 5px;
  6 + font-size: 12px;
  7 + li {
  8 + padding: 0;
  9 + margin: 7px 0;
  10 + list-style: none;
  11 + white-space: nowrap;
  12 + outline: 0;
  13 + a[draggable],
  14 + a[draggable="true"] {
  15 + user-select: none;
  16 + /* Required to make elements draggable in old WebKit */
  17 + -khtml-user-drag: element;
  18 + -webkit-user-drag: element;
  19 + }
  20 + &.drag-over {
  21 + > a[draggable] {
  22 + background-color: @primary-color;
  23 + color: white;
  24 + opacity: 0.8;
  25 + }
  26 + }
  27 + &.drag-over-gap-top {
  28 + > a[draggable] {
  29 + border-top: 2px @primary-color solid;
  30 + }
  31 + }
  32 + &.drag-over-gap-bottom {
  33 + > a[draggable] {
  34 + border-bottom: 2px @primary-color solid;
  35 + }
  36 + }
  37 + &.filter-node {
  38 + > a {
  39 + color: @error-color!important;
  40 + font-weight: bold!important;
  41 + }
  42 + }
  43 + ul {
  44 + margin: 0;
  45 + padding: 0 0 0 18px;
  46 + }
  47 + a {
  48 + display: inline-block;
  49 + padding: 1px 5px;
  50 + border-radius: 2px;
  51 + margin: 0;
  52 + cursor: pointer;
  53 + text-decoration: none;
  54 + vertical-align: top;
  55 + color: #666;
  56 + transition: all 0.3s ease;
  57 + &:hover {
  58 + background-color: tint(@primary-color, 90%);
  59 + }
  60 + &.@{tree-prefix-cls}-node-selected {
  61 + background-color: tint(@primary-color, 80%);
  62 + }
  63 + }
  64 + span {
  65 + &.@{tree-prefix-cls}-checkbox {
  66 + margin: 2px 4px 0 0;
  67 + }
  68 + &.@{tree-prefix-cls}-switcher,
  69 + &.@{tree-prefix-cls}-iconEle {
  70 + margin: 0;
  71 + width: 16px;
  72 + height: 16px;
  73 + line-height: 16px;
  74 + display: inline-block;
  75 + vertical-align: middle;
  76 + border: 0 none;
  77 + cursor: pointer;
  78 + outline: none;
  79 + }
  80 + &.@{tree-prefix-cls}-icon_loading {
  81 + &:after {
  82 + display: inline-block;
  83 + //.iconfont-font("\e6a1");
  84 + animation: loadingCircle 1s infinite linear;
  85 + color: @primary-color;
  86 + }
  87 + }
  88 + &.@{tree-prefix-cls}-switcher {
  89 + &.@{tree-prefix-cls}-switcher-noop {
  90 + cursor: auto;
  91 + }
  92 + &.@{tree-prefix-cls}-roots_open,
  93 + &.@{tree-prefix-cls}-center_open,
  94 + &.@{tree-prefix-cls}-bottom_open,
  95 + &.@{tree-prefix-cls}-noline_open {
  96 + //.antTreeSwitcherIcon();
  97 + }
  98 + &.@{tree-prefix-cls}-roots_close,
  99 + &.@{tree-prefix-cls}-center_close,
  100 + &.@{tree-prefix-cls}-bottom_close,
  101 + &.@{tree-prefix-cls}-noline_close {
  102 + //.antTreeSwitcherIcon();
  103 + //.ie-rotate(3);
  104 + &:after {
  105 + transform: rotate(270deg) scale(0.5);
  106 + }
  107 + }
  108 + }
  109 + }
  110 + }
  111 + &-child-tree {
  112 + display: none;
  113 + &-open {
  114 + display: block;
  115 + }
  116 + }
  117 + &-treenode-disabled {
  118 + >span,
  119 + >a,
  120 + >a span {
  121 + color: #ccc;
  122 + cursor: not-allowed;
  123 + }
  124 + }
  125 + &-icon__open {
  126 + margin-right: 2px;
  127 + vertical-align: top;
  128 + }
  129 + &-icon__close {
  130 + margin-right: 2px;
  131 + vertical-align: top;
  132 + }
5 133 }
6 134 \ No newline at end of file
... ...
test/routers/tree.vue
1 1 <template>
2   -
  2 + <Tree
  3 + :data.sync="treeData"
  4 + :checkable="true"
  5 + :multiple="true"
  6 + :on-select="selectFn"
  7 + :on-check="checkFn"></Tree>
3 8 </template>
4 9 <script>
5 10 export default {
6   - props: {},
7   - data () {
8   - return {};
  11 + data: function() {
  12 + return {
  13 + treeData: [{
  14 + title: 'parent 1',
  15 + selected: false,
  16 + node: [{
  17 + title: 'parent 1-0',
  18 + expand: true,
  19 + disabled: true,
  20 + node: [{
  21 + title: 'leaf',
  22 + disableCheckbox: true
  23 + }, {
  24 + title: 'leaf',
  25 + }]
  26 + }, {
  27 + title: 'parent 1-1',
  28 + checked: true,
  29 + node: [{
  30 + title: '<span style="color: red">sss</span>',
  31 + }]
  32 + }]
  33 + }]
  34 + }
9 35 },
10   - computed: {},
11   - methods: {}
12   - };
13   -</script>
14 36 \ No newline at end of file
  37 + methods: {
  38 + selectFn(data){
  39 + console.log(data);
  40 + },
  41 + checkFn(data){
  42 + console.log(data);
  43 + }
  44 + }
  45 + }
  46 +</script>
... ...