【问题标题】:v-for causing actions to be applied to all divsv-for 使动作应用于所有 div
【发布时间】:2017-12-25 04:30:12
【问题描述】:

之前我问过一个关于在 Vue 中删除自定义截断过滤器的问题。请在此处查看问题:

Removing a Vue custom filter on mouseover

但是,我没有提到我正在使用 v-for 循环,当我将鼠标悬停在一个 div 上时,我注意到循环中的所有 div 都应用了相同的操作。我不确定如何只定位悬停在上面的 div。这是我的模板:

 <div id="tiles">
    <button class="tile" v-for="(word, index) in shuffled" @click="clickWord(word, index)" :title="word.english">
      <div class="pinyin">{{ word.pinyin }}</div>
      <div class="eng" @mouseover="showAll = true" @mouseout="showAll = false">
        <div v-if="showAll">{{ word.english }}</div>
        <div v-else>{{ word.english | truncate }}</div>
      </div>
    </button>
  </div>

以及返回的数据:

  data(){
    return {
      currentIndex: 0,
      roundClear: false,
      clickedWord: '',
      matchFirstTry: true,
      showAll: false,
    }
  },

如果您了解 Vue,我将不胜感激。谢谢!

【问题讨论】:

    标签: javascript vue.js vuejs2


    【解决方案1】:

    在您的示例中,showAll 用于 v-for 生成的每个按钮,以确定是否显示 word.english 值的完整文本。这意味着,无论何时触发任何 .eng 类 div 的 mouseover 事件,都会为每个按钮将相同的 showAll 属性设置为 true。


    我会用最初设置为nullshowWordIndex 属性替换showAll 布尔值:

    data() {
      showWordIndex: null,
    },
    

    然后在模板中,将showWordIndex 设置为mouseover 处理程序中单词的index(以及mouseleave 处理程序中的null):

    <button v-for="(word, index) in shuffled" :key="index">
      <div class="pinyin">{{ word.pinyin }}</div>
      <div 
        class="eng" 
        @mouseover="showWordIndex = index" 
        @mouseout="showWordIndex = null" 
      >
        <div v-if="showWordIndex === index">{{ word.english }}</div>
        <div v-else>{{ word.english | truncate }}</div>
      </div>
    </button>
    

    Here's a working fiddle.


    更好的做法是制作一个新组件来封装v-for 中呈现的所有内容的功能和模板,将每个word 对象的属性作为props 传递给子组件。

    这样,您仍然可以像在示例中一样使用showAll 属性,但您可以在子组件的范围内定义它。所以现在showAll 属性只会影响与其相关的组件的实例。

    下面是一个例子:

    Vue.component('tile', {
      template: '#tile',
      props: ['pinyin', 'english'],
      data() {
        return { showAll: false };
      },
      filters: {
        truncate: function(value) {
          let length = 50;
          if (value.length <= length) {
            return value;
          } else {
            return value.substring(0, length) + '...';
          }
        }
      },
    })
    
    new Vue({
      el: '#app',
      data() {
        return {
          words: [
            {pinyin: 1, english: "really long string that will be cut off by the truncate function"},
            {pinyin: 2, english: "really long string that will be cut off by the truncate function"},
            {pinyin: 3, english: "really long string that will be cut off by the truncate function"},
            {pinyin: 4, english: "really long string that will be cut off by the truncate function"},
          ],
        }
      }
    })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.1/vue.min.js"></script>
    <div id="app">
      <tile v-for="word, i in words" v-bind="word" :key="word"></tile>
    </div>
    
    <script id="tile" type="x-template">
      <button :title="english">
        <div class="pinyin">{{ pinyin }}</div>
        <div class="eng" @mouseover="showAll = true" @mouseout="showAll = false">
          <div v-if="showAll">{{ english }}</div>
          <div v-else>{{ english | truncate }}</div>
        </div>
      </button>
    </script>

    【讨论】:

      【解决方案2】:

      为了做到这一点,您不能使用计算属性(正如我最初在您链接的我的答案中建议的那样),因为您需要了解您所处的上下文。也就是说,您如果您将showAll 属性应用于每个单独的实例,则可以使用过滤器。如果您在数据模型中预先声明这一点,则该属性将是反应性的,您可以在 mouseover 和 mouseout 上单独切换每个项目。

      模板:

      <div id="app">
        <div id="tiles">
          <div class="tile" v-for="(word, index) in shuffled" :title="word.english">
            <div class="pinyin">{{ word.pinyin }}</div>
            <div class="eng" @mouseover="word.showAll = true" @mouseout="word.showAll = false">
              {{ word.english | truncate(word) }}
            </div>
          </div>
        </div>
      </div>
      

      js:

      new Vue({
          el: '#app',
          data() {
              return {
                  shuffled: [
                      { english: 'here', showAll: false}, 
                      { english: 'are', showAll: false }, 
                      { english: 'there', showAll: false },
                      { english: 'words', showAll: false }
                  ],
                  currentIndex: 0,
                  roundClear: false,
                  clickedWord: '',
                  matchFirstTry: true,
              }
          },
          filters: {
              truncate: function(value, word) {
                  console.log(word)
                  let length = 3;
                  if (word.showAll || value.length <= length) return value;
      
                  return value.substring(0, length) + '...';
              }
          },
      })
      

      查看工作JSFiddle

      关键是将showAll 应用于每个单词实例,然后将该单词实例传递回过滤器,以便我们可以检查 showAll 属性的值。只要您预先声明它,Vue 的反应系统就会为您处理其余的事情。

      请注意,在此示例中,没有必要在 v-if/else 中使用两个元素。带有过滤器的单个元素可以完美运行。

      【讨论】:

        猜你喜欢
        • 2022-09-30
        • 2018-11-03
        • 2018-11-08
        • 2020-08-18
        • 2021-04-01
        • 2018-01-25
        • 2020-10-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多