【问题标题】:Selecting and unselecting nodes in tree view - vuejs在树视图中选择和取消选择节点 - vuejs
【发布时间】:2018-05-14 04:20:04
【问题描述】:

我是 VueJS 的新手。我一直致力于自定义 vuejs 文档中的树视图示例:Example

在树视图中选择一个项目时,我无法理解如何取消选择,即取消设置先前选择的项目的类。我尝试过的一些方法包括

  • 使用 Vue.prototype 设置全局变量并在计算函数中访问它,在这种情况下计算函数甚至不会运行。
  • 我知道传递的事件对象。使用它和 jQuery,删除先前选择的 div 的类会起作用,但这似乎是一种 hack。
  • 在单击事件上设置data 中选定项的数组,并在计算函数中访问它。这也行不通。

有什么方法可以工作还是我不明白?

我正在处理的 codepen 链接:Codepen。要选择一个节点,只需单击该节点并尝试选择其他一些节点。上一个节点没有被清除。

谢谢!

更新:

以下答案有效,但如果单击其他地方,它将删除选定的类。我想要一个解决方案,只有当我单击其他节点时才会删除所选类。我所要做的就是创建一个事件总线并将先前选择的组件对象存储在父变量中。单击新节点时,将发出一个全局事件,主实例方法将监听该事件。在那里,它将设置一个布尔值,该值将取消设置先前的组件选择,另一个布尔值将选定的类设置为新的组件对象。我不确定是否存在更好的方法。

更新了 codepen 并进行了一些更改:CodePen link

【问题讨论】:

    标签: javascript vue.js vuejs2


    【解决方案1】:

    这和VueJS无关,我们必须通过在文件夹节点获得焦点时设置所需的css属性来玩CSS。

    //https://github.com/vuejs/Discussion/issues/356
    // demo data
    Vue.prototype.$selectedNode = []
    var data = {
      name: 'My Tree',
      children: [{
          name: 'hello'
        },
        {
          name: 'wat'
        },
        {
          name: 'child folder',
          children: [{
              name: 'child folder',
              children: [{
                  name: 'hello'
                },
                {
                  name: 'wat'
                }
              ]
            },
            {
              name: 'hello'
            },
            {
              name: 'wat'
            },
            {
              name: 'child folder',
              children: [{
                  name: 'hello'
                },
                {
                  name: 'wat'
                }
              ]
            }
          ]
        }
      ]
    }
    
    // define the item component
    Vue.component('item', {
      template: '#item-template',
      props: {
        model: Object
      },
      data: function() {
        return {
          open: false,
          selectedNode: []
        }
      },
      computed: {
        isFolder: function() {
          return this.model.children &&
            this.model.children.length
        },
        setChevronClass: function() {
          return {
            opened: this.isFolder && this.open,
            closed: this.isFolder && !this.open,
            folderChevronSpan: this.isFolder
          }
        },
        setSelected: function() {
          if (this.selectedNode.length > 0 && this.selectedNode[0].title == this.model.name)
            return true;
          else
            return false;
        }
      },
      methods: {
        toggle: function() {
          if (this.isFolder) {
            this.open = !this.open
            this.$refs.toggler.focus();
          }
        },
        changeType: function() {
          if (!this.isFolder) {
            Vue.set(this.model, 'children', [])
            this.addChild()
            this.open = true
          }
        },
        addChild: function() {
          this.model.children.push({
            name: 'new stuff'
          })
        },
        selectNode: function() {
          this.selectedNode = [];
          this.selectedNode.push({
            'title': this.model.name,
            'isSelected': true
          });
        }
      }
    })
    
    // boot up the demo
    var demo = new Vue({
      el: '#demo',
      data: {
        treeData: data
      }
    })
    body {
      font-family: Menlo, Consolas, monospace;
      color: #444;
    }
    
    .item {
      cursor: pointer;
    }
    
    .folderTitleSpan:hover {
      font-weight: bold;
      border: 1px solid darkblue;
    }
    
    .folderTitleSpan:focus,
    li span:nth-child(1):focus+.folderTitleSpan {
      background-color: darkblue;
      color: white;
    }
    
    .node,
    .add {
      list-style-type: none;
      padding-left: 10px !important;
    }
    
    .folderChevronSpan::before {
      color: #444;
      content: '\25b6';
      font-size: 10px;
      margin-left: -1em;
      position: absolute;
      transition: -webkit-transform .1s ease;
      transition: transform .1s ease;
      transition: transform .1s ease, -webkit-transform .1s ease;
      -webkit-transition: -webkit-transform .1s ease;
    }
    
    .folderChevronSpan.opened::before {
      transform: rotate(90deg);
      -webkit-transform: rotate(90deg);
    }
    
    ul {
      padding-left: 1em;
      line-height: 1.5em;
      list-style-type: dot;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17-beta.0/vue.js"></script>
    <!-- item template -->
    <script type="text/x-template" id="item-template">
      <li>
        <span :class="setChevronClass" tabindex="0" ref="toggler" @click="toggle">  
      </span>
        <span @click="selectNode" tabindex="1" :class="{folderTitleSpan: isFolder}">
          {{ model.name }}
          </span>
        <span v-if="isFolder">[{{ open ? '-' : '+' }}]</span>
    
        <ul v-show="open" v-if="isFolder">
          <item class="item node" v-for="(model, index) in model.children" :key="index" :model="model">
          </item>
          <li class="add" @click="addChild">+</li>
        </ul>
      </li>
    </script>
    
    <p>(You can double click on an item to turn it into a folder.)</p>
    
    <!-- the demo root element -->
    <ul id="demo">
      <item class="item node" :model="treeData">
      </item>
    </ul>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多