具有独特模型的表头中的多个选择输入

kat*_*son 7 vue.js

我正在从采用以下格式的后端接收数据

[ 
    [ 
        [ "123", "21/11/2013", "Data", "Data" ], 
        [ "234", "22/11/2013", "Data", "Data" ], 
        [ "345", "12/09/2018", "Data", "Data" ], 
    ], 
    [ 
        [ "123", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data" ], 
        [ "234", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data" ], 
        [ "345", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data" ] 
    ] 
]
Run Code Online (Sandbox Code Playgroud)

每个 fileData 代表一个表,因此在上面的示例中它应该生成两个表。里面的数据包含一个表格行,所以上面的每个表格都有两行。为了实现这一点,我正在做类似以下的事情。

<table class="table" v-for="(file, index) in fileData" :key="index">
    <tbody>
        <tr v-for="(row, index2) in file":key="index2">
          <td v-for="(data, index3) in row" :key="index3">
            {{ data }}
          </td>
        </tr>
    </tbody>
</table>
Run Code Online (Sandbox Code Playgroud)

这一切似乎工作正常。但是,我使用的数据没有标题,但我需要为包含选择的每一列提供一个标题。因此,我添加了以下内容

<table class="table" v-for="(file, index) in fileData" :key="index">
    <thead>
        <tr>
           <th scope="col" v-for="(col, index2) in file[index]" :key="index2">
             <b-form-select v-model="options.value" :options="options"></b-form-select>
           </th>
        </tr>
    </thead>
</table>
Run Code Online (Sandbox Code Playgroud)

这似乎再次奏效。我的问题是我希望用户使用选择来定义列代表什么。目前,如果我选择某些东西,它们都会改变。

我制作了这个小提琴作为例子https://jsfiddle.net/mhyv62bt/1/

如何使选择独立,是否也可以在选择后删除选项?

谢谢

这似乎为每个表生成正确数量的标题列。

更新 我的设置略有不同,因此尝试将其与我的项目相适应。因此,我创建了文件 THheadSelect.vue

<template id="theadselect">
  <thead>
  <tr>
    <th
      v-for="(i,index) in this.length_"
      :key="index"
    >
      <select
        v-model="headers[index]">
        <option disabled value="">
          Please select one
        </option>

        <option
          v-if="headers[index]"
          selected
        >
          {{headers[index]}}
        </option>
        <option
          v-for="option in filteredOptions"
          :key="option"
        >
          {{option}}
        </option>
      </select>
    </th>
  </tr>
  </thead>
</template>

<script>
export default {
  mounted () {
    this.$emit('update:headers',
      this.headers
        .concat(Array.from({ length: this.length_ }, _ => ''))
        .slice()
    )
  },
  props: {
    options: {
      type: Array,
      required: true
    },
    length: Number,
    headers: {
      type: Array,
      required: true
    }
  },
  computed: {
    length_: {
      get () {
        return this.length || this.options.length
      },
      set (l) {
        this.$emit('update:length', l)
      }
    },
    filteredOptions () {
      return this.options.filter(
        option => !this.headers.includes(option)
      )
    }
  }
}
</script>
Run Code Online (Sandbox Code Playgroud)

然后我尝试在我的页面中使用它

<template>
  <div>
    <b-form
      novalidate
      @submit.stop.prevent=""
    >
      <div class="row">
        <div class="col-12">
          <table class="table table-bordered" v-for="(file, index) in fileData" :key="index">
            <thead
              is="THeadSelect"
              :options="['option1', 'option2', 'option3']"
              :headers.sync="headers"
            ></thead>
            <tbody>
            <tr v-for="(row, index2) in file" :key="index2">
              <td v-for="(data, index3) in row" :key="index3">
                {{ data }}
              </td>
            </tr>
            </tbody>
          </table>
        </div>
      </div>
    </b-form>
  </div>
</template>

<script>
import { THeadSelect } from '@/components/common/THeadSelect'

export default {
  components: {
    THeadSelect
  },
  computed: {
    fileData () {
      return this.$store.getters.fileData
    }
  },
  data () {
    return {
      headers: [],
      length: 10,
    }
  }
}
</script>
Run Code Online (Sandbox Code Playgroud)

不过还是有点乱。每个表只显示 3 个选择。此外,如果我选择表 1 中的一个选项,它会选择表 2 中的相同选项。如果您查看我的原始小提琴,您可以看到我正在尝试使用的初始数据,因此总会有两个表。

Est*_*iaz 2

我想你可以把它作为一个组件

标题:

可能的用法:

<thead
  is="THeadSelect"
  :options="header_row"
  :length="length /*defaults to options.length*/"
  :headers.sync="headers"
></thead>
Run Code Online (Sandbox Code Playgroud)

组件选项

//*.js
const THeadSelect = {
  template: "#theadselect",
  mounted(){
    // make sure headers is populated
    this.$emit("update:headers",
     this.headers
     .concat(Array.from({length:this.length_}, _=>""))
     .slice()
    )
  },
  props: {
    options: {
      type: Array,
      required: true,
    },
    length: Number,
    headers: {
      type: Array,
      required: true
    }
  },
  computed:{
    length_:{
      get(){
        return this.length || this.options.length
      },
      set(l){
        this.$emit("update:length",l)
      }
    },
    filteredOptions(){
      return this.options.filter(
        option => !this.headers.includes(option)
      )
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

模板

// *.html 
<template id="theadselect">
  <thead>
    <tr>
      <th
        v-for="(i,index) in length_"
        :key="index"
      >
        <select 
          v-model="headers[index]">
          <option disabled value="">
            Please select one
          </option>

          <option
            v-if="headers[index]"
            selected
          >
            {{headers[index]}}
          </option>
          <option
           v-for="option in filteredOptions"
           :key="option"
          >
            {{option}}
          </option>
        </select>
      </th>
    </tr>
  </thead>
</template>
Run Code Online (Sandbox Code Playgroud)

例子

<thead
  is="THeadSelect"
  :options="header_row"
  :length="length /*defaults to options.length*/"
  :headers.sync="headers"
></thead>
Run Code Online (Sandbox Code Playgroud)
//*.js
const THeadSelect = {
  template: "#theadselect",
  mounted(){
    // make sure headers is populated
    this.$emit("update:headers",
     this.headers
     .concat(Array.from({length:this.length_}, _=>""))
     .slice()
    )
  },
  props: {
    options: {
      type: Array,
      required: true,
    },
    length: Number,
    headers: {
      type: Array,
      required: true
    }
  },
  computed:{
    length_:{
      get(){
        return this.length || this.options.length
      },
      set(l){
        this.$emit("update:length",l)
      }
    },
    filteredOptions(){
      return this.options.filter(
        option => !this.headers.includes(option)
      )
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

对于正文,可以考虑 headers 数组的值。也许放置数组索引或对象属性而不是当前选项值

因此,对于多个表,我们可以考虑:

// *.html 
<template id="theadselect">
  <thead>
    <tr>
      <th
        v-for="(i,index) in length_"
        :key="index"
      >
        <select 
          v-model="headers[index]">
          <option disabled value="">
            Please select one
          </option>

          <option
            v-if="headers[index]"
            selected
          >
            {{headers[index]}}
          </option>
          <option
           v-for="option in filteredOptions"
           :key="option"
          >
            {{option}}
          </option>
        </select>
      </th>
    </tr>
  </thead>
</template>
Run Code Online (Sandbox Code Playgroud)

对于 TableSelect:

const THeadSelect = {
  template: "#theadselect",
  mounted(){
    // make sure headers is populated
    this.$emit("update:headers",
     this.headers
     .concat(Array.from({length:this.length_}, _=>""))
     .slice()
    )
  },
  props: {
    options: {
      type: Array,
      required: true,
    },
    length: Number,
    headers: {
      type: Array,
      required: true
    }
  },
  computed:{
    length_:{
      get(){
        return this.length || this.options.length
      },
      set(l){
        this.$emit("update:length",l)
      }
    },
    filteredOptions(){
      return this.options.filter(
        option => !this.headers.includes(option)
      )
    }
  }
}

new Vue({

  components: {THeadSelect},
  data(){
    return {
      headers: [],
      length: 10
    }
  },
  template: "#root"
}).$mount('#app')
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<template id="theadselect">
  <thead>
    <tr>
      <th
        v-for="(i,index) in length_"
        :key="index"
      >
        <select 
          v-model="headers[index]">
          <option value="">
            Please select one
          </option>
          <option
            v-if="headers[index]"
            selected
          >
            {{headers[index]}}
          </option>
          <option
           v-for="option in filteredOptions"
           :key="option"
          >
            {{option}}
          </option>
        </select>
      </th>
    </tr>
  </thead>
</template>

<template id="root">
  <div>
  <table>
    <caption>Sample usage with select</caption>
    <thead 
      is="THeadSelect"
      :options="['option1', 'option2', 'option3']"
      :headers.sync="headers"
    ></thead>
    <tbody>
      <tr>
        <td
          v-for="(prop, index) in headers"
          :key="prop+index"
        >
          {{ prop || '?'}}
        </td>
      </tr>
    </tbody>
  </table>
  </div>
</template>
<table id="app"></table>
Run Code Online (Sandbox Code Playgroud)

上面的代码有错误,但由于懒惰和缺少 linter,所以我会顺其自然 - 因为它提供了基本的想法。


以及codesandbox 上的运行示例:

https://lbm8l.csb.app/