Развлечения ради.
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>