简体   繁体   English

添加用于编辑所选元素中的数组对象键的“输入” - Vue.js

[英]Adding 'input' used to edit array object key in selected elements - Vue.js

i need to add an input field used to edit the title in the currently selected element component (selection was done by clicking).我需要在当前选定的元素组件中添加一个用于编辑titleinput字段(选择是通过单击完成的)。 The problem is that there should be one input and work for each selected element .问题是每个选定的元素都应该有一个输入和工作 I couldn't find a similar task and solving on the Internet.我在互联网上找不到类似的任务和解决方案。 Maybe someone will tell you how to do it?也许有人会告诉你怎么做?

ItemsList.vue component: ItemsList.vue组件:

<template>
    <input type="text" placeholder="Edit selected items"/>
    <div class="items-col">
        <ul class="items-list">
            <Item v-for="item in items" :key="item" :title="item.title"/>
        </ul>
    </div>
</template>

<script>
import Item from '@/components/Item.vue'
export default {
    data() {
        return {
            items: [
                { title: 'item 1' },
                { title: 'item 2' },
                { title: 'item 3' },
                { title: 'item 4' },
                { title: 'item 5' },
                { title: 'item 6' }
            ]
        }
    },
    components: {
        Item
    }
}
</script>

Item.vue component: Item.vue组件:

<template>
    <li class="item" @click="isActive = !isActive" :class="{ active: isActive }">{{ title }}</li>
</template>

<script>

export default {
    name: 'ItemsList',
    data() {
        return {
            isActive: false
        }
    },
    props: {
        title: String
    }
}
</script>

<style>
    .item.active {
        color: red;
    }
</style>

You might want to reconsider which component should be responsible of knowing which item is active at any point of time: hint: it should be the parent/consuming component.您可能需要重新考虑哪个组件应该负责知道哪个项目在任何时间点处于活动状态:提示:它应该是父/消费组件。 That is because you:那是因为你:

  1. Have only a single input field, which means only one item can be edited at any point of time只有一个输入字段,这意味着在任何时间点只能编辑一个项目
  2. You want to let the parent/consuming component to be the single source of truth of which item is actually active您想让父/消费组件成为哪个项目实际处于活动状态的唯一真实来源

Therefore, the first thing you should do is to ensure that isActive is a prop on the Item component, while the parent ItemList component keeps track of which is active at any point.因此,您应该做的第一件事是确保isActiveItem组件上的一个 prop,而父ItemList组件会随时跟踪哪个处于活动状态。

Then, it is simply a matter of:那么,这只是一个问题:

  • Implementing a toggling logic for the isActive flag.isActive标志实现切换逻辑。 The flag is updated when a native click event is fired from the Item component.当从Item组件触发本机单击事件时,会更新该标志。 For the toggling logic, we can simply toggle between a zero-based index of the click item, or -1 , which we used to indicate that nothing is active.对于切换逻辑,我们可以简单地在点击项的从零开始的索引或-1之间切换,我们用它来表示没有任何活动。
  • Using v-bind:value and a computed property to reflect the value of the currently active item.使用v-bind:value和一个计算属性来反映当前活动项的值。 We can simply retrieve it using this.items[this.activeIndex] on the parent component我们可以简单地在父组件上使用this.items[this.activeIndex]来检索它
  • Listening to the onInput event and then updating the correct item监听onInput事件,然后更新正确的项目

See proof-of-concept below:请参阅下面的概念验证:

 Vue.component('item-list', { template: '#item-list-template', data() { return { items: [{ title: 'item 1' }, { title: 'item 2' }, { title: 'item 3' }, { title: 'item 4' }, { title: 'item 5' }, { title: 'item 6' } ], activeIndex: -1, } }, methods: { onItemClick(index) { this.activeIndex = this.activeIndex === index ? -1 : index; }, setActiveItemValue(event) { const foundItem = this.items[this.activeIndex]; if (!foundItem) return; return this.items[this.activeIndex].title = event.currentTarget.value; } }, computed: { activeItemValue() { return this.items[this.activeIndex]?.title ?? ''; } } }); Vue.component('item', { template: '#item-template', props: { isActive: Boolean, title: String } }); new Vue({ el: '#app' });
 li.active { background-color: yellow; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <div id="app"> <item-list></item-list> </div> <script type="text/x-template" id="item-list-template"> <div> <input type="text" placeholder="Edit selected items" :value="activeItemValue" @input="setActiveItemValue" /> <div class="items-col"> <ul class="items-list"> <item v-for="(item, i) in items" :key="i" :title="item.title" :isActive="activeIndex === i" @click.native="onItemClick(i)" /> </ul> </div> </div> </script> <script type="text/x-template" id="item-template"> <li class="item" :class="{ active: isActive }">{{ title }}</li> </script>

If you want a solution with your current components (not the cleanest) , you can actually emit an event to the parent component when you activate an element that event should containe the index of the object in the items array如果您想要使用当前组件(不是最干净的)的解决方案,当您激活一个元素时,您实际上可以向父组件发出一个事件,该事件应包含项目数组中对象的索引

Then you can use the index to get and set the title variable , here is an example :然后你可以使用索引来获取和设置标题变量,这是一个例子:

Item.vue项目.vue

<template>
  <li class="item" @click="activateItem" :class="{ active: isActive }">{{ title }}</li>
</template>

<script>

export default {
  name: 'ItemsList',
  data() {
    return {
      isActive: false
    }
  },
  methods:{
    activateItem() {
      this.isActive = !this.isActive
      this.$emit('activatedItem', this.isActive ? this.index : null)
    }
  },
  props: {
    title: String,
    index: Number
  }
}
</script>

<style>
.item.active {
  color: red;
}
</style>

ItemList.vue项目列表.vue

<template>
  <div>
    <input type="text" placeholder="Edit selected items" @input="inputChange" :value="inputValue"/>
    <div class="items-col">
      <ul class="items-list">
        <Item v-for="(item, index) in items" :key="index" :title="item.title" :index="index" @activatedItem="itemSelected"/>
      </ul>
    </div>
  </div>
</template>

<script>
import Item from '@/components/Item.vue'
export default {
  data() {
    return {
      items: [
        { title: 'item 1' },
        { title: 'item 2' },
        { title: 'item 3' },
        { title: 'item 4' },
        { title: 'item 5' },
        { title: 'item 6' }
      ],
      selectedIndex: null,
      inputValue: ''
    }
  },
  methods:{
    itemSelected(index){
        this.selectedIndex = index;
        if(this.selectedIndex != null) {
          this.inputValue = this.items[this.selectedIndex].title;
        }
    },
    inputChange(event){
      this.inputValue = event.target.value;
      if(this.selectedIndex != null){
        this.items[this.selectedIndex].title = this.inputValue
      }
    }
  },
  components: {
    Item
  }
}
</script>

You should also be aware that with the component Item you have given you can select more than one item !您还应该知道,使用您提供的组件 Item,您可以选择多个项目!

For your second question you should just change the index to match the one from the array , for instance if rowIndex starts with 1 :对于您的第二个问题,您应该只更改索引以匹配数组中的索引,例如,如果 rowIndex 以 1 开头:

onItemClick(index, rowIndex) {
    let correctIndex = (index + (this.itemsPerRow * (rowIndex - 1));
    this.activeIndex = this.activeIndex === correctIndex ? -1 : correctIndex);
},

Thank's guys, it's working fine.谢谢各位,运行正常。

Another question for this task:此任务的另一个问题:

How to make it work for the condition that the elements are in a row of 3 items?如何使其在元素位于 3 个项目的行中的条件下工作?

For example i need to get this final effect:例如我需要得到这个最终效果:


<ul class="items-list">
    //my Item.vue component
    <li class="item" :class="{ active: isActive }">item 1</li>
    //my Item.vue component
    <li class="item" :class="{ active: isActive }">item 2</li>
    //my Item.vue component
    <li class="item" :class="{ active: isActive }">item 3</li>
</ul>
<ul class="items-list">
    //my Item.vue component
    <li class="item" :class="{ active: isActive }">item 4</li>
    //my Item.vue component
    <li class="item" :class="{ active: isActive }">item 5</li>
    //my Item.vue component
    <li class="item" :class="{ active: isActive }">item 6</li>
</ul>

I wrote a method that separates items by 3 in a row and after your solution, I have the following:我写了一个方法,将项目连续 3 分隔,在您的解决方案之后,我有以下内容:

ItemsList.vue component: ItemsList.vue组件:

<template>
    <div class="items-col">
        <input type="text" placeholder="Edit selected items" :value="activeItemValue" @input="setActiveItemValue" />
        <ul class="items-list" v-for="index in rowCount" :key="index">
            <Item v-for="(item, i) in itemCountInRow(index)" :key="i" :title="item.title"  :isActive="activeIndex === i" @click="onItemClick(i)"/>
        </ul>
    </div>
</template>

<script>

import Item from '@/components/Item.vue'

export default {
    name: 'ItemsList',
    data() {
        return {
            items: [
                { title: 'item 1' },
                { title: 'item 2' },
                { title: 'item 3' },
                { title: 'item 4' },
                { title: 'item 5' },
                { title: 'item 6' },
            ],
            activeIndex: -1,
            itemsPerRow: 3
        }
    },
    components: {
        Item
    },
    computed: {
        rowCount(){
            return Math.ceil(this.items.length / this.itemsPerRow);
        },
        activeItemValue() {
            return this.items[this.activeIndex]?.title ?? '';
        }
    },
    methods: {
        onItemClick(index) {
            this.activeIndex = this.activeIndex === index ? -1 : index;
        },
        setActiveItemValue(event) {
            const foundItem = this.items[this.activeIndex];
            if (!foundItem) return;
            
            return this.items[this.activeIndex].title = event.currentTarget.value;
        },
        itemCountInRow(index){
            return this.items.slice((index - 1) * this.itemsPerRow, index * this.itemsPerRow)
        }
    }
}
</script>

Now when i click on the item your method only works for the first list.现在,当我单击该项目时,您的方法仅适用于第一个列表。

Is it possible to make it work together with the division of 3 items per row?是否可以使其与每行 3 个项目的划分一起工作?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM