我尝试应用CSS
转换,因为我在淘汰组件之间切换,但我没有太多的快乐来实现这一目标。基本上我想要一个具有固定宽度的div
,但其内部内容将会改变。当它这样做时,我希望能够转换元素的重新调整大小。
ko.components.register("big", {
viewModel: function (vm) {
this.items = vm.value.items;
},
template: '<div class="big box" data-bind="foreach: items"><p class="item" data-bind="text: name"></p></div>'
});
ko.components.register("small", {
viewModel: function (vm) {
this.items = vm.value.items;
},
template: '<div class="small box" data-bind="foreach: items"><span class="item" data-bind="text: name"></span></div>'
});
var vm = {};
vm.componentName = ko.observable("small");
vm.items = ko.observableArray([{ name: "A" }, { name: "B" }, { name: "C" }]);
ko.applyBindings(vm);
setInterval(function() {
if(vm.componentName() === "small") { vm.componentName("big"); }
else { vm.componentName("small"); }
}, 3000);
&#13;
.box {
width: 200px;
-webkit-transition: height 2s;
transition: height 2s;
-webkit-transition: width 2s;
transition: width 2s;
}
.big {
border: thin solid black;
}
.small {
border: thin solid black;
padding: 10px 10px 10px 10px;
}
.item {
padding-left: 10px;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="component: { name: componentName, params: { value: $data } }">
</div>
&#13;
所以我问了一些模糊相关的Why doesn't CSS transition get applied?,其中我了解到DOM正在为新值重新构建(在这种情况下是新模板),因此CSS转换不适用。
那里的解决方案很简单(确保你反复绑定同一个东西)。但对于组件,我真的不想将两个模板组合在一起,这样我才能获得转换。还有另一种方法可以达到这个目的吗?
答案 0 :(得分:2)
你实际上是在切换组件意味着正在重构DOM,所以我没有看到使用CSS进行动画制作的方法。
你可以做的是建立你自己的绑定处理程序,它使用Javascript为你做动画:
ko.bindingHandlers.animatingComponent = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
var value = valueAccessor();
var componentName = value.name;
// create a new observable so we can delay the moment ko's component
// binding builds the new component
var actualComponentName = ko.observable(componentName());
componentName.subscribe(function(newComponent) {
$(element).hide(500, function() {
actualComponentName(newComponent);
$(element).show(500);
});
});
ko.bindingHandlers.component.init(element, function() {
return { name: actualComponentName, params: value.params};
}, allBindings, viewModel, bindingContext);
}
};
ko.components.register("big", {
viewModel: function (vm) {
this.items = vm.value.items;
},
template: '<div class="big box" data-bind="foreach: items"><p class="item" data-bind="text: name"></p></div>'
});
ko.components.register("small", {
viewModel: function (vm) {
this.items = vm.value.items;
},
template: '<div class="small box" data-bind="foreach: items"><span class="item" data-bind="text: name"></span></div>'
});
var vm = {};
vm.componentName = ko.observable("small");
vm.items = ko.observableArray([{ name: "A" }, { name: "B" }, { name: "C" }]);
ko.applyBindings(vm);
setInterval(function() {
if(vm.componentName() === "small") { vm.componentName("big"); }
else { vm.componentName("small"); }
}, 3000);
.box {
width: 200px;
}
.big {
border: thin solid black;
}
.small {
border: thin solid black;
padding: 10px 10px 10px 10px;
}
.item {
padding-left: 10px;
}
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="animatingComponent: { name: componentName, params: { value: $data } }">
</div>
答案 1 :(得分:1)
它只花了一天的大部分时间,但我完成了过渡工作。我有一个变量,它记住了最后一个显示大小(它是组件发生变化时的起始位置)。当组件发生变化时,我将隐藏的可见性和大小设置为默认值,这样我就可以得到div的预期大小。然后我将其调整为最后一个显示尺寸并使其可见,然后将其调整为新尺寸,然后进行转换。
请注意,我还必须稍微改变一下CSS。
ko.components.register("big", {
viewModel: function (vm) {
this.items = vm.value.items;
},
template: '<div class="big box" data-bind="style:$root.boxSize, foreach: items, sizeGet:$root.boxSize"><p class="item" data-bind="text: name"></p></div>'
});
ko.components.register("small", {
viewModel: function (vm) {
this.items = vm.value.items;
},
template: '<div class="small box" data-bind="style:$root.boxSize, foreach: items, sizeGet:$root.boxSize"><span class="item" data-bind="text: name"></span></div>'
});
var unclipped;
ko.bindingHandlers.sizeGet = {
init: function (element, valueAccessor) {
var sizer = valueAccessor();
sizer({
height: '',
width: '',
visibility: 'hidden'
});
var nextUnclipped = {
height: element.scrollHeight + 'px',
width: element.scrollWidth + 'px',
visibility: 'visible'
};
if (unclipped) sizer(unclipped);
unclipped = nextUnclipped;
setTimeout(function () {
sizer(unclipped);
}, 0);
}
};
var vm = (function () {
var activeComponent = ko.observable('small'),
defaultSize = {
width: '',
height: ''
},
boxSize = ko.observable(defaultSize);
return {
componentName: activeComponent,
boxSize: boxSize,
items: ko.observableArray([{
name: "A"
}, {
name: "Big"
}, {
name: "Cat"
}, {
name: "Dropping"
}])
};
}());
ko.applyBindings(vm);
var i = setInterval(function () {
if (vm.componentName() === "small") {
vm.componentName("big");
} else {
vm.componentName("small");
}
}, 3000);
setTimeout(clearInterval.bind(null, i), 45000);
&#13;
.box {
width:200px;
-webkit-transition: height 2s, width 2s;
transition: height 2s, width 2s;
overflow:hidden;
}
.big {
border: thin solid black;
}
.small {
border: thin solid black;
padding: 10px 10px 10px 10px;
}
.item {
padding-left: 10px;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div data-bind="component: { name: componentName, params: { value: $data } }">
</div>
&#13;