vue.js - дерево меню с быстрым фильтром: складывается и фильтр не работает вместе - PullRequest
0 голосов
/ 19 сентября 2018

Мотивация

Я хочу создать дерево меню с панелью поиска для выделения пунктов меню.Я придумал следующую реализацию:

const treeConfig = [
  {
    label: 'User',
    children: [
      {
        label: 'User group'
      },
      {
        label: 'Permissions'
      }
    ]
  },
  {
    label: 'Tests',
    children: [
      {
        label: 'Unit tests'
      },
      {
        label: 'Visual regression tests'
      }
    ]
  },
  {
    label: 'Other stuff'
  }
];

Vue.component('tree', {
  template: '#tree',
  props: ['nodes'],
  data() {
    return {
      showChildren: true
    };
  },
  methods: {
    toggleChildren() {
      this.showChildren = !this.showChildren;
    }
  }
});

const vm = new Vue({
  el: '#app',
  data: {
    quicksearch: ''
  },
  computed: {
    nodes() {
      const self = this;
      
      function getTree(nodes) {
        return nodes.map((node) => {
          node.label_ = node.label;
          node.label_ = node.label.replace(new RegExp(self.quicksearch, 'gi'), '<mark>$&</mark>');
          if (node.children) {
            node.children = getTree(node.children);
          }
          return node;
        });
      }
      
      return getTree(treeConfig);
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>

<div id="app">
  <input type="search" placeholder="Quick search" v-model="quicksearch">
  <tree :nodes="nodes"></tree>
</div>

<template id="tree">
  <ul>
    <li
      v-for="node in nodes"
    >
    <span
      v-if="node.children"
      @click="toggleChildren()"
    >
      <i v-show="!showChildren">+</i>
      <i v-show="showChildren">-</i>
    </span>
    <span v-html="node.label_"></span>
    <tree
      v-if="node.children"
      v-show="showChildren"
      :nodes="node.children"
    ></tree>
    </li>
  </ul>
</template>

Задача

С кодом выше поддеревья не могут быть свернуты независимо.Щелчок по одному из + или - сворачивает каждое поддерево.

Второй подход

Поэтому я попытался использовать компонент tree-item вместо компонента tree:

const treeConfig = [
  {
    label: 'User',
    children: [
      {
        label: 'User group'
      },
      {
        label: 'Permissions'
      }
    ]
  },
  {
    label: 'Tests',
    children: [
      {
        label: 'Unit tests'
      },
      {
        label: 'Visual regression tests'
      }
    ]
  },
  {
    label: 'Other stuff'
  }
];

Vue.component('tree-item', {
  template: '#tree-item',
  props: ['node'],
  data() {
    return {
      showChildren: true
    };
  },
  methods: {
    toggleChildren() {
      this.showChildren = !this.showChildren;
    }
  }
});

const vm = new Vue({
  el: '#app',
  data: {
    quicksearch: '',
    title: 'Hello filtered tree!'
  },
  computed: {
    nodes() {
      const self = this;
      
      function getTree(nodes) {
        return nodes.map((node) => {
          node.label_ = node.label;
          node.label_ = node.label.replace(new RegExp(self.quicksearch, 'gi'), '<mark>$&</mark>');
          if (node.children) {
            node.children = getTree(node.children);
          }
          return node;
        });
      }
      
      return getTree(treeConfig);
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>

<div id="app">
  <input type="search" placeholder="Quick search" v-model="quicksearch">
  <ul>
    <tree-item
      v-for="node in nodes"
      :node="node"
    ></tree-item>
  </ul>
</div>

<template id="tree-item">
  <li>
    <span
      v-if="node.children"
      @click="toggleChildren()"
    >
      <i v-show="!showChildren">+</i>
      <i v-show="showChildren">-</i>
    </span>
    <span v-html="node.label_"></span>
    <ul
      v-if="node.children"
      v-show="showChildren"
    >
      <tree-item
        v-for="node in node.children"
        :node="node"
      ></tree-item>
    </ul>
  </li>
</template>

Проблема

Теперь можно свернуть каждое поддерево отдельно, но быстрый фильтр не работает.Кажется, что объект nodes не реагирует.

Где моя ошибка мышления?Любые предложения приветствуются.

Ответы [ 2 ]

0 голосов
/ 19 сентября 2018

похоже, проблема с массивами.просто добавьте :key="node.label_" к тегу tree-item в шаблоне, вот и все.

0 голосов
/ 19 сентября 2018

Вы должны взглянуть на это: Реакционная способность в глубине Когда ваш вычисленный только что вычислен изменением значения быстрого поиска, он не запускает реконструкцию других компонентов (в этом случае дерево-много), потому что он не наблюдает за объектом глубоко.

Простая работа здесь заключается в том, чтобы полностью повлиять на новый результат отображения массива.

const treeConfig = [
  {
    label: 'User',
    children: [
      {
        label: 'User group'
      },
      {
        label: 'Permissions'
      }
    ]
  },
  {
    label: 'Tests',
    children: [
      {
        label: 'Unit tests'
      },
      {
        label: 'Visual regression tests'
      }
    ]
  },
  {
    label: 'Other stuff'
  }
];

Vue.component('tree-item', {
  template: '#tree-item',
  props: ['node'],
  data() {
    return {
      showChildren: true
    };
  },
  methods: {
    toggleChildren() {
      this.showChildren = !this.showChildren;
    }
  },
  watch : {
    node(n) {
      console.log(n)
    }
  },
  created() {
    console.log(this.node);
  }
});

const vm = new Vue({
  el: '#app',
  data: {
    quicksearch: '',
    title: 'Hello filtered tree!',
    nodes : []
  },
  methods : {    
    getNodes() {
      const self = this;
      
      function getTree(nodes) {
        return nodes.map((node) => {
          node.label_ = node.label;
          node.label_ = node.label.replace(new RegExp(self.quicksearch, 'gi'), '<mark>$&</mark>');
          if (node.children) {
            node.children = getTree(node.children);
          }
          return node;
        });
      }
      
      return getTree(treeConfig);
    }
  },
  created(){
    this.nodes = this.getNodes();
  },
  watch : {
    quicksearch(q) {
      this.nodes = this.getNodes();
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>

<div id="app">
  <input type="search" placeholder="Quick search" v-model="quicksearch">
  <ul>
    <tree-item
      v-for="node in nodes"
      :node="node"
    ></tree-item>
  </ul>
</div>

<template id="tree-item">
  <li>
    <span
      v-if="node.children"
      @click="toggleChildren()"
    >
      <i v-show="!showChildren">+</i>
      <i v-show="showChildren">-</i>
    </span>
    <span v-html="node.label_"></span>
    <ul
      v-if="node.children"
      v-show="showChildren"
    >
      <tree-item
        v-for="node in node.children"
        :node="node"
      ></tree-item>
    </ul>
  </li>
</template>
...