同步 2+ md-虚拟重复

Sync 2+ md-virtual-repeat

我希望能够同步 2 个 md-virtual-repeat 列表,以便它们的滚动位置相同。

我尝试使用 md-top-index,这让我很接近,但在滚动时它们并不总是对齐。 http://codepen.io/anon/pen/NxKvmy

HTML

<div ng-app="virtualRepeatScrollToDemo" ng-controller="AppCtrl as ctrl" class="scroll-demo">
  <md-content class="md-padding">
    <div class="wrapper">
      <md-virtual-repeat-container id="vertical-container" md-top-index="ctrl.topIndex">
        <div md-virtual-repeat="item in ctrl.items"
            class="repeated-item" ng-class="{header: item.header}" flex>
          {{item.text}}
        </div>
      </md-virtual-repeat-container>
    </div>    
    <div class="wrapper">
      <md-virtual-repeat-container id="vertical-container" md-top-index="ctrl.topIndex">
        <div md-virtual-repeat="item in ctrl.items"
            class="repeated-item" ng-class="{header: item.header}" flex>
          {{item.text}}
        </div>
      </md-virtual-repeat-container>
    </div>    
  </md-content>
</div>

JS

(function () {
  'use strict';
    angular
      .module('virtualRepeatScrollToDemo', ['ngMaterial'])
      .controller('AppCtrl', function($scope) {
        this.years = [];
        this.items = [];
        var currentYear = new Date().getFullYear();
        var monthNames = ['January', 'February', 'March', 'April', 'May', 'June','July', 'August', 'September', 'October', 'November', 'December'];
        for (var y = currentYear; y >= (currentYear-20); y--) {
          this.years.push(y);
          this.items.push({year: y, text: y, header: true});
          for (var m = 11; m >= 0; m--) {
            this.items.push({year: y, month: m, text: monthNames[m]});
          }
        }    
      });
})();

CSS

.wrapper {
    width: 400px;
    float:left;
    margin-left:20px;
}

#vertical-container {
  height: 292px;
  width: 400px;
}

#vertical-container .repeated-item {
  border-bottom: 1px solid #ddd;
  box-sizing: border-box;
  height: 40px;
  padding-top: 10px;
}

#vertical-container .repeated-item.header {
    background-color: #3F51B5;
    color: white;
    text-align: center;
    font-weight: bold;
}

#vertical-container md-content {
  margin: 16px;
}

md-virtual-repeat-container {
  border: solid 1px grey;
}

.md-virtual-repeat-container .md-virtual-repeat-offsetter {
  padding-left: 16px;
}

我一直在寻找一种骇人听闻的方法来观察 scroll/transform 位置,但我看不出有什么方法可以做到。有谁知道这样做的方法吗?

谢谢。

下面是同步虚拟重复的指令。你这样使用它:

<md-virtual-repeat-container md-orient-horizontal
    vr-scrollsync="scroll">
    <div md-virtual-repeat="...">
        ...
    </div>
</md-virtual-repeat-container>

在您的范围内,您必须将滚动 属性 初始化为一个空对象:

$scope.scroll = {};

(或者至少我对 Angular 的了解还不够,不知道如何在不这样做的情况下在指令实例之间共享值——帮助欢迎讨论该主题)

我用水平重复测试了它,但它应该也适用于垂直。


angular.module("vrScrollsync", []).directive("vrScrollsync", ["$timeout", function($timeout) {
    return {
        scope: {
            scroll: "=vrScrollsync"
        },
        link: function(scope, element, attrs) {
            /**
             * These flags avoid infinite recursion between Javascript 
             * event firing and Angular value changes.
             */
            var skipWatch = false;
            var skipEvent = false;

            /**
             * The scroller child of the virtual repeat container.
             * It is not there yet at link time, so we set up a timer to obtain it.
             */
            var scroller = null;

            $timeout(function() {
                scroller = element.find(".md-virtual-repeat-scroller");
                scroller.bind("scroll", function() {
                    if (skipEvent) {
                        skipEvent = false;
                        return;
                    }
                    update(true);
                });
            });

            function update(skipWatchIfChanged) {
                var oldval = scope.scroll; 
                var newval = {
                        top: scroller[0].scrollTop,
                        left: scroller[0].scrollLeft
                };
                scope.scroll = newval;

                var changed = oldval && (oldval.top != newval.top || oldval.left != newval.left)
                if (skipWatchIfChanged && changed) skipWatch = true;

                scope.$apply();
            }

            scope.$watch("scroll", function(v, old) {
                if (skipWatch) {
                    skipWatch = false;
                    return;
                }
                if (scroller) {
                    skipEvent = true;
                    scroller[0].scrollTop = v.top;
                    scroller[0].scrollLeft = v.left;
                }
            });
        }
    }; 
}]);