使用动态css属性的Vue列表rending

时间:2017-10-16 14:15:26

标签: javascript vue.js

我试图制作类似旋转木马的项目列表(例如那些iOS原生日期/时间选择器),这些项目可以向上或向下移动。

每个项目的位置基于模型的top属性,最终以绝对定位分配给每个列表项元素。

我设法让它在一个方向上工作,所以如果你按“上升”,它就会按照我想要的功能运行(你可以在下面的代码片段中查看)。另一方面,当我将相同的代码用于另一个方向时(除了我将.pop()函数切换为.shift().unshift()改为.push()),它的工作方式不同,特别是项目值被重新分配,但没有任何动作。

我注意到,在第二种情况下,列表项目由于某种原因从头开始呈现,尽管有项目键。因此,坐标转换不会发生。

如何使此机制在两个方向都有效?请随意查看我准备的片段:



Vue.component('list-component', {
  template: '#list-component',
  name: 'list-componet',
  data() {
  	return {
    	model: [],
      activeIndex: null,
      itemHeight: 56,
    }
  },
  methods: {
    shiftWheel(direction) {
      if (direction === 'up') {
        const value = this.model[0].value - 1;

        this.model.map((v) => {
          v.top += this.itemHeight;
        });

        this.model.pop();
        this.model.unshift({
          value,
          top: -this.itemHeight
        });

      } else {
        const value = this.model[this.model.length - 1].value + 1;

        this.model.shift();

        this.model.forEach((v) => {
          v.top -= this.itemHeight;
        });
        this.model.push({
          value,
          top: this.itemHeight * 5
        });
      }
  	}
  },
  mounted() {
    const quantity = 5 + 2;
  
    this.top = -56;

    const currentYear = moment().year;
    const toTheSides = Math.floor(quantity / 2);

    this.activeIndex = quantity - toTheSides - 1;

    const start = moment().clone().subtract(toTheSides, 'Y');

    this.model = Array(quantity).fill().map((v, i) => {
      const value = start.clone();
      start.add(1, 'Y');
      return {
        value: value.year(),
        top: i * this.itemHeight - this.itemHeight
      };
    });
  }
});

new Vue({ 
    el: '#app'
});

.container {
  position: relative;
  overflow: hidden;
  height: 280px;
  width: 50px;
}

.wrapper {
  display: flex;
  align-items: center;
}

.buttons {
  position: relative;
  z-index: 999;
}

.md-wheel-item {
  padding: 16px 0;
  display: flex;
  position: absolute;
  flex: 1;
  align-items: center;
  justify-content: center;
  transition: top .2s ease-in-out;
  will-change: top;
  &.is-active {
    color: red;
  }
}

<script src="https://unpkg.com/vue@2.4.2/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/moment@2.19.1/moment.min.js"></script>

<script type="text/x-template" id="list-component">
	<div class="wrapper">
  	<div class="container">
    	<div v-for="(item, iIndex) in model"
				:key="item.value"
      	class="md-wheel-item"
      	:class="{'is-active': iIndex === activeIndex}"
      	:style="{height: itemHeight + 'px', top: item.top + 'px'}">
      	{{ item.value || item }}
    	</div>
    </div>
    <div class="buttons">
    	<button @click.prevent="shiftWheel('up')">Go up</button>
   		<button @click.prevent="shiftWheel('down')">Go down</button>
    </div>
	</div>
</script>

<div id="app">
  <div id="content">   
      <list-component></list-component>
  </div>
</div>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:0)

使用此github问题(github.com/vuejs/vue/issues/4834)作为参考,看起来我只需要使用transition-group

  

它们不是重新创建的(项目),而是由insertBefore移动。如果在转换期间移动了具有转换的元素,则转换将被中断。当完成所有操作时,键确保元素在DOM中的正确位置结束,但不保证它们在过程中永远不会移动。这是确保具有一致结果的简洁算法所必需的。这可能会在未来得到改善,但这不是非常关键的事情