• Как совместить сортировку и фильтрацию?

    @GrayHorse
    Развлечения ради.
    Composition API [RU] + Script Setup [RU].

    Собственно, демо: https://sfc.vuejs.org/#

    Код:
    <script setup>
      import {ref, computed, watchEffect} from "vue";
    
      const phones = ref([
        { title: "iPhone 12", company: "Apple", price: 65000 },
        { title: "Galaxy S20", company: "Samsung", price: 63000 },
        { title: "Galaxy A10", company: "Samsung", price: 38000 },
        { title: "iPhone 10", company: "Apple", price: 45000 },
        { title: "Xiaomi Redmi 8", company: "Xiaomi", price: 42000 },
      ]);
    
    
      const companySearch = ref("");
      const filteredList = computed(() => {
        if (!companySearch.value) {
          return phones.value;
        }
        const search = companySearch.value.trim().toLowerCase();
        return phones.value.filter(elem => elem.company.toLowerCase().startsWith(search)); // .includes(search)
      });
    
    
      const sortParam = ref("");
      
      const sortByTitle   = (p1, p2) => p1.title.localeCompare(p2.title, undefined, {sensitivity: "base"});
      const sortByCompany = (p1, p2) => p1.company.localeCompare(p2.company, undefined, {sensitivity: "base"});
      const sortByPrice   = (p1, p2) => p1.price - p2.price;
    
      const sortedList = ref([]);
      watchEffect(() => {
        const array = filteredList.value; //const array = [...filteredList.value];
        if (sortParam.value === "title") {
          sortedList.value = array.sort(sortByTitle);
        } else if (sortParam.value === "company") {
          sortedList.value = array.sort(sortByCompany);
        } else if (sortParam.value === "price") {
          sortedList.value = array.sort(sortByPrice);
        } else {
          sortedList.value = array;
        }
      });
    </script>


    Версия с инвертированием сортировки по второму клику (ссылка на демо в комменте):
    <script setup>
      import {ref, computed} from "vue";
    
      const phones = ref([
        { title: "iPhone 12", company: "Apple", price: 65000 },
        { title: "Galaxy S20", company: "Samsung", price: 63000 },
        { title: "Galaxy A10", company: "Samsung", price: 38000 },
        { title: "iPhone 10", company: "Apple", price: 45000 },
        { title: "Xiaomi Redmi 8", company: "Xiaomi", price: 42000 },
      ]);
    
    
      const companySearch = ref("");
      const filteredList = computed(() => {
        if (!companySearch.value) {
          return phones.value;
        }
        const search = companySearch.value.trim().toLowerCase();
        return phones.value.filter(elem => elem.company.toLowerCase().startsWith(search)); // .includes(search)
      });
    
      /** @type {import("vue").Ref<("title"|"company"|"price")>} */
      const orderBy = ref("title");
      const orders = ref({ // if `true` — an order is reversed
        title: false,
        company: false,
        price: false,
      });
      const isOrderReversed = computed(() => orders.value[orderBy.value]);
      function toggleOrder() {
        orders.value[orderBy.value] = !orders.value[orderBy.value];
      }
      /** @param {"title"|"company"|"price"} value */
      function setOrderBy(value) {
        if (orderBy.value === value) {
          toggleOrder();
        }
        orderBy.value = value;
      };
    
      const {compare} = new Intl.Collator(undefined, {sensitivity: "base"});
      function comparator(pre, cur) {
        const k = isOrderReversed.value ? -1 : 1;    
        if (orderBy.value === "title") {
          return compare(pre.title, cur.title) * k;
        } else if (orderBy.value === "company") {
          return compare(pre.company, cur.company) * k;
        } else if (orderBy.value === "price") {
          return (pre.price - cur.price) * k;
        }
        return 0;
      }
      const sortedList = computed(() => { 
        return filteredList.value.sort(comparator);
      });
    </script>
    Ответ написан
    2 комментария