<p>This one does not have <code>v-bind:keys</code> set. Notice the incorrect DOM, color, and structure when sorting. Works when changing a few innocuous things, like if using <code><span></code>s instead of <code><div></code>s in the $slots or wrapping <code>render-vnodes</code> with an extra <code><div></code></p>
<div id="app">
<button @click="$root.$emit('sort1')">Toggle Sorting
</button>
<color-izer>
<div>GREEN 2</div>
<div>RED 1</div>
<div>GREEN 1</div>
<div>RED 2</div>
<div>RED 3</div>
<div>GREEN 3</div>
</color-izer>
<p>This one has <code>v-bind:keys</code>. It works fine</p>
<button @click="$root.$emit('sort2')">Toggle Sorting
</button>
<color-izer set-keys="true">
<div>GREEN 2</div>
<div>RED 1</div>
<div>GREEN 1</div>
<div>RED 2</div>
<div>RED 3</div>
<div>GREEN 3</div>
</color-izer>
</div>
html, body{
max-width: 800px;
}
Vue.component("render-vnodes", {
functional: true,
render: function(createElement, ctx){
return createElement("div", {}, ctx.props.vnodes);
}
});
Vue.component("color-izer", {
template: "<div><div style='display:inline-block;border:1px solid black;padding:4px;'>SORTED? {{sorted}}</div><br>" +
"<render-vnodes v-if='sorted' :vnodes='nodesForColor(\"r\")'></render-vnodes>" +
"<render-vnodes v-if='sorted' :vnodes='nodesForColor(\"g\")'></render-vnodes>" +
"<slot v-if='!sorted'></slot></div>",
mounted: function(){
if(this.setKeys) {
this.$slots.default.forEach(function(vnode, index){
vnode.key = index;
});
}
this.$slots.default
.filter(function(a){return !!a.children;})
.forEach(function(vnode){
var color = vnode.children[0].text[0].toLowerCase();
var style = {
backgroundColor: color === "r" ? "#DD7777" : "#77DD77",
display: "inline-block",
padding: "5px",
fontFamily: "Arial"
};
vnode.data = vnode.data || {};
vnode.data.style = style;
})
var self = this;
this.$root.$on(this.setKeys ? "sort2" : "sort1", function(){
self.sorted = !self.sorted;
self.$forceUpdate();
});
},
props: ["setKeys"],
data: function(){
return {sorted: false};
},
methods: {
nodesForColor: function(color){
var self = this;
return this.$slots.default.slice()
.filter(function(a){return !!a.children;})
.filter(function(vnode){
return vnode.children[0].text[0].toLowerCase() === color;
});
}
}
});
new Vue({
el: "#app"
});
This Pen doesn't use any external CSS resources.