如何抽象以下模式? (使用Vue.js)

时间:2016-12-16 03:38:57

标签: javascript vue.js

我正在学习Vue.js.我喜欢它轻巧。我正在创建一个用户界面,其中有“设备”对象。每个设备都有输入和输出,可以通过mDevice.inputs或mDevice.outputs访问。输入和输出是具有输入/输出名称,id和类型的对象列表。

设备在屏幕上显示为div,在div上有文本“Inputs”和“Outputs”。可以将鼠标悬停在这些标签上,并显示mDevice.inputs和mDevice.outputs。这是那部分:

<div v-on:mouseover="device.showInputs = !device.showInputs">inputs</div>
                            <ul class="io-list" v-if="device.showInputs">
                                <li v-for="(e, idx) in device.inputs">
                                    {{e.id}} - {{ e.the_type }}
                                    <div 
                                        v-on:mouseover="e.showAvailableOutputs = !e.showAvailableOutputs"
                                        class="xpull-right" style="display:inline;font-size:1.5em;">»</div>
                                    <ul class="sub-io-list" v-if="e.showAvailableOutputs"
                                        v-on:mouseleave="e.showAvailableOutputs = !e.showAvailableOutputs">
                                        <li style="white-space:nowrap" v-for="io in setupOutputs">
                                            ({{io.device.model}}) - {{io.the_type}}
                                        </li>
                                    </ul>
                                </li>
                            </ul>

                            <div v-on:mouseover="device.showOutputs = !device.showOutputs">outputs</div>
                            <ul class="io-list" v-if="device.showOutputs">
                                <li v-for="(e, idx) in device.outputs">
                                    {{e.id}} - {{ e.the_type }}
                                    <div 
                                        v-on:mouseover="e.showAvailableInputs = !e.showAvailableInputs"
                                        class="xpull-right" style="display:inline;font-size:1.5em;">»</div>
                                    <ul class="sub-io-list" v-if="e.showAvailableInputs"
                                        v-on:mouseleave="e.showAvailableInputs = !e.showAvailableInputs">
                                        <li style="white-space:nowrap" v-for="io in setupInputs">
                                            ({{io.device.model}}) - {{io.the_type}}
                                        </li>
                                    </ul>
                                </li>
                            </ul>

列表是多级的(2)。这里有重复,我想抽象。

我试过了:

<template  v-for="x in ['inputs','outputs']">
                            <div v-on:mouseover="toggleShowIOs(device,x, false)">{{x}}</div>
                            <ul class="io-list" v-if="showIOs(device, x, false)">
                                <li v-for="(e, idx) in device[x]">
                                    {{e.id}} - {{ e.the_type }}
                                    <div 
                                        v-on:mouseover="toggleShowIOs(e,x, true)"
                                        class="xpull-right" style="display:inline;font-size:1.5em;">»</div>
                                    <ul class="sub-io-list" v-if="showIOs(e,x,true)"
                                        v-on:mouseleave="toggleShowIOs(e,x, true)">
                                        <li style="white-space:nowrap" v-for="io in setupOutputs">
                                            ({{io.device.model}}) - {{io.the_type}}
                                        </li>
                                    </ul>
                                </li>
                            </ul>
                            </template>

但是当传递给函数toggleShowIOs时,似乎x(天气是'输入'或'输出')不会持续存在。我在想,因为我没有在我的vue实例的data属性中声明它。

抽象这种创建多级菜单的最简单方法是什么?我是在正确的轨道上吗?我正在考虑创建一个组件。

还有一个问题,在数据或道具属性中放置函数有多糟糕?

编辑: 好吧,我想我越来越接近这个了。这就是我现在所拥有的:

Vue.component('hover-menu', {
    template: '#hover-menu-template',
    props: ['label','menuItems'],
    data : function() {
        return {
            show: false,
        }
    },
    methods: {
        flipAndEmit: function() {
            this.show = !this.show;
            this.$emit('flipAndEmit');
        }
    }
});

模板:

<template id="hover-menu-template">
    <div v-on:mouseover="flipAndEmit" v-on:mouseleave="flipAndEmit">
        <div>{{ label }} » </div>
        <ul v-if="show" style="display:inline;background-color:#5BE;">
            <li is="hover-menu"
                v-for="(item, index) in menuItems"
                v-bind:label="item.id"
                v-bind:menu-items="menuItems"></li>
        </ul>
    </div>
</template>


<hover-menu label="Inputs" :menu-items="device.inputs"></hover-menu>
<hover-menu label="Outputs" :menu-items="device.outputs"></hover-menu>

控制仍然不稳定,但我认为这是现在的答案。一旦它全部工作,我将在这里发布答案。如果你们中的任何人打败我,那就更好了。

1 个答案:

答案 0 :(得分:0)

终于明白了。我使用了Vue.js文档中的文件夹树示例来指导我。这是模板和html:

<template id="menu-template">
  <div>
  <div>{{menu.name}}
    <span v-if="menu.options.length > 0" v-on:mouseenter="showOptions = !showOptions">&gt;&gt;</span>
    <span v-else v-on:click="selectOption">OK</span>
  </div>
  <menu-children :options="menu.options" v-if="showOptions" v-on:went-out="showOptions = !showOptions"></menu-children>
  </div>
</template>  
<template id="menu-options-template">
  <ul class="list" v-on:mouseleave="sendUp">
    <li v-for="choice in options">
      <amenu-parent v-if="choice.options" :menu="choice"></amenu-parent>
      <span v-else>{{ choice.name }}</span>
    </li>
  </ul>
</template>

<div id="app">
  <div v-for="r in root">
    <amenu-parent :menu="r"></amenu-parent>
  </div>
</div>

这是js:

Vue.component('amenu-parent', {
  template: "#menu-template",
  props: ['menu'],
  data: function() {
    return {
      showOptions: false,
    }
  },
  methods: {
    selectOption: function(v) {
      alert('clicked');
    }
  }
});
Vue.component('menu-children', {
  template: "#menu-options-template",
  props: ['options'],
  methods: {
    sendUp: function() {
      this.$emit("went-out");
    }

  }
});

var app = new Vue({
  el: "#app",
  data: {
    root: [{
      name: 'a',
      options: [{
        name: '1',
        options: []
      }, {
        name: 'asdf',
        options: [{
          name: 'deep',
          options: []
        }]
      }]
    }, {
      name: 'number2',
      options: [{
        name: 'deep',
        options: []
      }]
    }]
  },
});

还有一些css:

body {
  font-size:1.8em;
}
.list > li {
  background-color:#EEE;
  width:300px;
}