2

Suppose I have three divs - A, B, and c - and I want to change their order when a user clicks "reorder". Eg, by putting B first, C second, and A third. What is the cleanest way to do this in Vue?

Edit: in reality, there is a lot of content in the divs, so doing something like { divs: ['A', 'B', 'C'] } with a v-for would get too messy.

let app = new Vue({
  el: '#app',
  methods: {
    reorder: function () {
    },
  },
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <div>A</div>
  <div>B</div>
  <div>c</div>
  <button v-on:click="reorder()">Reorder</button>
</div>
Adam Zerner
  • 17,797
  • 15
  • 90
  • 156

2 Answers2

7

Here is what I came up with:

  1. Use flexbox for the container with flex-direction: column
  2. Have CSS classes that set the order, eg. .one { order: 1 }
  3. Dynamically assign the CSS classes to elements based on how you want to order them.

let app = new Vue({
  el: '#app',
  data: {
    order: {
      a: 'one',
      b: 'two',
      c: 'three',
    },
  },
  methods: {
    reorder: function () {
      this.order.a = 'three';
      this.order.b = 'one';
      this.order.c = 'two';
    },
  },
});
#app {
  display: flex;
  flex-direction: column;
}

.one { order: 1; }
.two { order: 2; }
.three { order: 3; }
button { order: 4; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <div v-bind:class="order.a">A</div>
  <div v-bind:class="order.b">B</div>
  <div v-bind:class="order.c">C</div>
  <button v-on:click="reorder()">Reorder</button>
</div>
Adam Zerner
  • 17,797
  • 15
  • 90
  • 156
  • 2
    This will not be accessible as the dom DIVs will still be in default order and the tabbing might suffer. – Liam Feb 14 '21 at 07:41
4

I would say...

in data you have:

data: {
    return {
        blocks: [{
            type: 'ComponentA'
            content: {
                title: 'Foo',
                desc: 'lorem ipsum'
            }
        }, {
            type: 'ComponentB'
            content: {
                title: 'Bar',
                desc: 'lorem ipsum'
            }
        }, {
            type: 'ComponentC'
            content: {
                title: 'Baz',
                desc: 'lorem ipsum'
            }
        }]
    }
}

in the template you have:

  <component v-for="(block, i) in blocks" :key="i" :is="block.type"/>

and reorder shuffles the array: How to randomize (shuffle) a JavaScript array?

  • Hi Dario, thank you for your answer! I think that approach is great and makes a ton of sense. However, I meant `
    A
    ` to be more of a toy example. In reality, my real situation is a much bigger and more complicated div, and putting that markup in the data would get messy. Sorry for not making that clear in my original question.
    – Adam Zerner Mar 02 '19 at 22:36
  • Hey Adam, my bad, I totally missed that part of the question. I would still do it the same way. I will edit my answer. – Dario Cavanillas Mar 03 '19 at 07:13
  • Sorry to keep adding qualifications to the question, but I've got another one. My components all have a bunch of `v-bind` and `v-on` stuff. Is there a way to dynamically attach them to the component? I don't mean to be annoying with the qualifications, but I think they're important because I think that they'd apply to most people who are dealing with this situation, not just myself. – Adam Zerner Mar 04 '19 at 18:16
  • Hey, no worries. I think I might need to see an example to be able to see. Do you think this should be a different question? – Dario Cavanillas Mar 04 '19 at 18:26
  • 1
    Now that I think about it yeah, what I'm describing here to you is different from what I actually asked in the question. And I think the answer to each is different. For the question that I actually asked, I think that your answer is best! – Adam Zerner Mar 09 '19 at 00:21