Vue.Isotope icon indicating copy to clipboard operation
Vue.Isotope copied to clipboard

Vue 3?

Open gitFoxCode opened this issue 5 years ago • 7 comments

Is this library still being supported? Will it be on Vue.js 3.0?

gitFoxCode avatar Jan 11 '21 18:01 gitFoxCode

Yeah, Vue 3 support would be awesome!

jakobwinter avatar Mar 14 '21 11:03 jakobwinter

vue3 ?

kekekezi avatar Mar 07 '22 15:03 kekekezi

we want vue 3 version. that would be really awesome!!

aenzenith avatar Sep 21 '22 09:09 aenzenith

Ah, so this doesn't work with Vue 3, good to know! xD Vue 3 Support please! @David-Desmaisons

developerzblock avatar Nov 12 '22 00:11 developerzblock

is anyone found the alternative for vue3?

superdiazzz avatar Mar 25 '23 12:03 superdiazzz

A quick solution for when you need minimal filtering capabilities. Using Vue 3 and Tailwind.

<script setup>
// components/QuickIsotope.vue

import {computed, ref} from 'vue';

const catOne = computed(() =>
    'https://fakeimg.pl/480x320/C6011F/eae0d0/?retina=1&font=noto&text=1st Cat'
);
const catTwo = computed(() =>
    'https://fakeimg.pl/480x320/568203/eae0d0/?retina=1&font=noto&text=2nd Cat'
);
const catThree = computed(() =>
    'https://fakeimg.pl/480x320/720e9e/eae0d0/?retina=1&font=noto&text=3rd Cat'
);

const cards = ref([
    {
        id: 1,
        cat: 1,
        title: 'Lorem',
        href: catOne,
    },
    {
        id: 2,
        cat: 2,
        title: 'Ipsum',
        href: catTwo,
    },
    {
        id: 3,
        cat: 3,
        title: 'Dolor',
        href: catThree,
    },
    {
        id: 4,
        cat: 1,
        title: 'Sit',
        href: catOne,
    },
    {
        id: 5,
        cat: 2,
        title: 'Amet',
        href: catTwo,
    },
    {
        id: 6,
        cat: 3,
        title: 'Consectetur',
        href: catThree,
    },
    {
        id: 7,
        cat: 1,
        title: 'Adispicing',
        href: catOne,
    },
    {
        id: 8,
        cat: 2,
        title: 'Elit',
        href: catTwo,
    },
]);

const categories = ref([1, 2, 3]);

const setCategories = (cat = [1]) => {
    categories.value = cat;
};

const categoriesSelected = computed(() => {    
    return cards.value.filter((card) => {
        return categories.value.includes(card.cat);
    });
});
</script>

<template>
<div class="my-16 p-32 w-full bg-yellow-400">
    <button
        class="w-24 bg-orange-700 text-white rounded"
        @click="setCategories([1, 2, 3])"
    >
        All
    </button>
    
    <button
        class="w-24 bg-orange-700 text-white rounded ml-4"
        @click="setCategories([1])"
    >
        Cat 1
    </button>
    
    <button
        class="w-24 bg-orange-700 text-white rounded ml-4"
        @click="setCategories([2])"
    >
        Cat 2
    </button>
    
    <button
        class="w-24 bg-orange-700 text-white rounded ml-4"
        @click="setCategories([3])"
    >
        Cat 3
    </button>
    
</div>

<div class="grid grid-cols-4 place-items-center gap-24 w-full mb-32">
    <transition-group
        enter-active-class="transition duration-150 delay-150 ease-out"
        enter-from-class="opacity-0 scale-0"
        enter-to-class="opacity-100 scale-100"
        leave-active-class="transition duration-150 ease-in"
        leave-from-class="opacity-100 scale-100"
        leave-to-class="opacity-0 scale-0"
    >
        <div
            v-for="card in categoriesSelected"
            :key="card.id"
            :id="'card-' + card.id"
            class="w-48 h-32 bg-orange-700 rounded-2xl overflow-hidden"
        >
                <img
                    :src="card.href"
                    :alt="card.title"
                    class="w-full"
                />
        </div>
    </transition-group>
</div>
</template>

roenfeldt avatar Mar 29 '23 16:03 roenfeldt

Hey guys, This is the source code written by chatGpt4 for vue 3. Have a look.

import { merge } from "lodash";
import Isotope from "isotope-layout";
import { onMounted, onBeforeUnmount, onUpdated, ref, watch } from "vue";

function addClass(node, classValue) {
  if (node.data) {
    const initValue = !node.data.staticClass ? "" : node.data.staticClass + " ";
    node.data.staticClass = initValue + classValue;
  }
}

function getItemVm(elmt) {
  return elmt.__underlying_element;
}

export default {
  name: "isotope",

  props: {
    options: {
      type: Object,
      default: () => ({
        layoutMode: "masonry",
        masonry: {
          gutter: 10
        }
      })
    },
    itemSelector: {
      type: String,
      default: "item"
    },
    list: {
      type: Array,
      required: true
    }
  },

  setup(props, { slots, emit }) {
    const prevChildren = ref([]);
    const children = ref([]);
    const removedIndex = ref([]);

    const displayChildren = ref([]);

    const cleanupNodes = () => {
      removedIndex.value.reverse();
      removedIndex.value.forEach(index =>
        children.value.splice(index, 1)
      );
    };

    const link = () => {
      const slotElements = slots.default ? slots.default() : [];
      slotElements.forEach((slot, index) => {
        const elmt = slot.el;
        if (elmt) {
          elmt.__underlying_element = { vm: props.list[index], index };
        }
      });
    };

    const listen = () => {
      const listeners = [];
      Object.values(props.options.getSortData).forEach(sort => {
        props.list.forEach((collectionElement, index) => {
          const unwatch = watch(() => sort(collectionElement), () => {
            iso.value.updateSortData();
            iso.value._requestUpdate();
          });
          listeners.push(unwatch);
        });
      });
      return listeners;
    };

    const iso = ref(null);

    onMounted(() => {
      const options = merge({}, props.options);
      const update = object => {
        Object.entries(object).forEach(([key, value]) => {
          object[key] = itemElement => {
            const res = getItemVm(itemElement);
            return value.call(this, res.vm, res.index);
          };
        });
      };
      update(options.getSortData);
      update(options.getFilterData);
      if (options.filter) {
        options.filter = buildFilterFunction(options.filter);
      }

      link();
      const listeners = listen();
      iso.value = new Isotope(document.querySelector(".isotope"), options);
      iso.value._requestUpdate = () => {
        if (iso.value._willUpdate) return;
        iso.value._willUpdate = true;
        setTimeout(() => {
          iso.value.arrange();
          iso.value._willUpdate = false;
        });
      };
      emit("isotope-instance", iso.value);

      onBeforeUnmount(() => {
        listeners.forEach(unwatch => unwatch());
        iso.value = null;
      });
    });

    onUpdated(() => {
      if (!iso.value) return;

      const newChildren = Array.from(document.querySelector(".isotope").children);
      const added = newChildren.filter(child => !prevChildren.value.includes(child));
      const removed = prevChildren.value.filter(child => !newChildren.includes(child));

      prevChildren.value = newChildren;

      cleanupNodes();
      link();

      if (removed.length === 0 && added.length === 0) return;

      const listeners = listen();

      iso.value.remove(removed);
      iso.value.insert(added);
      iso.value._requestUpdate();

      onBeforeUnmount(() => {
        listeners.forEach(unwatch => unwatch());
        iso.value = null;
      });
    });

    const buildFilterFunction = name => {
      const filter = props.options.getFilterData[name];
      const filterListener = watch(
        () => props.list.map((el, index) => filter(el, index)),
        () => iso.value._requestUpdate()
      );
      onBeforeUnmount(() => {
        filterListener();
      });
      return filter;
    };

    const sort = name => {
      let sortOption = name;
      if (typeof name === "string") {
        sortOption = { sortBy: name };
      }
      arrange(sortOption);
      emit("sort", name);
    };

    const filter = name => {
      const filterOption = buildFilterFunction(name);
      arrange({ filter: filterOption });
      emit("filter", name);
    };

    const unfilter = () => {
      arrange({ filter: () => true });
      emit("filter", null);
    };

    const layout = name => {
      let layoutOption = name;
      if (typeof name === "string") {
        layoutOption = { layoutMode: name };
      }
      arrange(layoutOption);
      emit("layout", layoutOption);
    };

    const arrange = option => {
      iso.value.arrange(option);
      emit("arrange", option);
    };

    const shuffle = () => {
      iso.value.shuffle();
      emit("shuffle");
      emit("sort", null);
    };

    const getFilteredItemElements = () => iso.value.getFilteredItemElements();

    const getElementItems = () => iso.value.getElementItems();

    return {
      iso,
      sort,
      filter,
      unfilter,
      layout,
      arrange,
      shuffle,
      getFilteredItemElements,
      getElementItems
    };
  },

  render() {
    const map = {};
    const prevChildren = this.prevChildren;
    const rawChildren = this.$slots.default || [];
    const children = this.children;
    const removedIndex = this.removedIndex;

    rawChildren.forEach(elt => addClass(elt, this.itemSelector));

    for (let i = 0; i < rawChildren.length; i++) {
      const c = rawChildren[i];
      if (c.type && c.type.name) {
        if (c.key != null && String(c.key).indexOf("__vlist") !== 0) {
          children.push(c);
          map[c.key] = c;
        } else {
          console.log(`Warning template error: isotope children must be keyed: <${c.type.name}>`);
        }
      }
    }

    const displayChildren = [...children];

    if (prevChildren) {
      for (let i = 0; i < prevChildren.length; i++) {
        const c = prevChildren[i];
        if (!map[c.key]) {
          displayChildren.splice(i, 0, c);
          removedIndex.push(i);
        }
      }
    }

    return h("div", { class: "isotope" }, displayChildren);
  }
};

What do you guys think? It should work?

ktm72 avatar Jun 01 '23 18:06 ktm72