const filteredProducts = computed(() => {
const search = searchQuery.value.toLowerCase();
return search.length > 2
? data.value.filter(n => n.title.toLowerCase().includes(search))
: null;
});
<ul v-if="filteredProducts" class="search-result">
<li v-if="!filteredProducts.length">
<h3>ничего не найдено</h3>
</li>
<li v-for="n in filteredProducts">
<div>
<Image :src="n.image" :alt="n.title" width="40" height="40" />
</div>
<h3>{{ n.title }}</h3>
<div>
<p>{{ n.price }}</p>
</div>
</li>
</ul>
v-for
.// если гарантируется отсутствие thead и tfoot, или их содержимое также должно учитываться
const { rows } = table;
// если tbody один
const [ { rows } ] = table.tBodies;
// если tbody несколько
const rows = Array.prototype.flatMap.call(table.tBodies, n => [...n.rows]);
// или
const rows = [].concat(...Array.from(table.tBodies, n => [...n.children]));
// или
const rows = table.querySelectorAll('tbody tr');
const middle = arr => arr[arr.length >> 1];
// или
const middle = arr => arr[Math.floor(arr.length / 2)];
// или
const middle = arr => arr[Math.round(~-arr.length / 2)];
// или
const middle = arr => arr[(arr.length - arr.length % 2) / 2];
const cell = middle(middle(rows).cells);
// или
const cell = middle([].reduce.call(rows, (acc, n) => (acc.push(...n.children), acc), []));
// или, без получения строк
const cell = middle(table.querySelectorAll('tbody td'));
const el = document.querySelector('p');
const strings = [ 'hello, world!!', 'fuck the world', 'fuck everything' ];
const delay = 100;
function Typewriter(el, strings, delay) {
let i = 0;
let length = 0;
return setInterval(() => {
if (++length > strings[i].length) {
i = -~i % strings.length;
length = 0;
}
el.textContent = strings[i].slice(0, length);
}, delay);
}
const intervalId = Typewriter(el, strings, delay);
// хотим остановить, делаем так: clearInterval(intervalId);
function Typewriter(el, strings, delay) {
let timeoutId = null;
(function step(i, length) {
length = -~length % -~strings[i].length;
i = (i + !length) % strings.length;
el.innerText = strings[i].substring(0, length);
timeoutId = setTimeout(step, delay, i, length);
})(0, 0);
return () => clearTimeout(timeoutId);
}
const stop = Typewriter(el, strings, delay);
// хотим остановить, делаем так: stop();
При повторном нажатии на кнопку максимальным числом выскакивает число удалённого li.
remove
приведёт к исчезновению элемента из lis
? Искать максимальный элемент следует среди тех, что всё ещё присутствуют на странице, а не тех, что были изначально - то есть, или надо получать элементы непосредственно перед поиском, или коллекция элементов должна быть динамической.function max(data, key = n => n) {
const getVal = key instanceof Function ? key : n => n[key];
let result = null;
for (const n of data) {
const val = getVal(n);
if (!result || result[1] < val) {
result = [ n, val ];
}
}
return result?.[0];
}
document.querySelector('button').addEventListener('click', function(e) {
max(this, n => +n.textContent)?.remove();
e.target.disabled = !this.length;
}.bind(document.querySelector('ul').children));
map.setBehaviors(map.behaviors.filter(n => n !== 'drag'));
- if (map && typeof map.setCenter === 'function' && typeof map.setZoom === 'function') {
- map.setCenter(15)(marker.geometry.getCoordinates(), 15);
- map.setZoom(15);
- }
+ map.setLocation({
+ center: markersCollection.find(n => n.id === officeId).coordinate,
+ zoom: 15,
+ });
использую библиотеку rc-slider, к сожалению она не предлагает возможности...
1 переносим на следующий разряд влево, а 5 пишем в текущий
item.isAdded = true
const quantity = ref(1)
const quantity = defineModel('quantity');
<CartItem
v-for="n in cart"
v-bind="n"
:key="n.id"
@update:quantity="updateQuantity(n, $event)"
@remove="removeFromCart(n)"
/>
const updateQuantity = (item, quantity) => item.quantity = quantity;
const totalPrice = computed(() => cart.value.reduce((acc, n) => acc + n.price * n.quantity, 0));
function getCombinations($arr, $keys = [], $vals = []) {
return ($n = $arr[count($keys)] ?? null)
? array_merge(...array_map(
fn($k) => getCombinations(
$arr,
[ ...$keys, $k ],
[ ...$vals, ...$n[$k] ]
),
array_keys($n)
))
: [ implode('_', $keys) => $vals ];
}
getMaxQuestionsLeft(question, depth) {
return Math.max(
depth,
...question.nextQuestions.map(n => {
return this.getMaxQuestionsLeft(this.questions[n], depth + 1);
})
);
},
get progress() {
const ac = this.answersCount;
return Math.floor(ac / (ac + this.getMaxQuestionsLeft(this.question, 0)) * 100);
},
get maxQuestionsLeft() {
let result = 0;
for (const stack = [ [ this.question, 0 ] ]; stack.length;) {
const [ q, d ] = stack.pop();
result = Math.max(result, d);
stack.push(...q.nextQuestions.map(n => [ this.questions[n], -~d ]));
}
return result;
},
get progress() {
const { answersCount: ac } = this;
return ac / (ac + this.maxQuestionsLeft) * 100 | 0;
},
history: createMemoryHistory(),
Vue-router не изменяет url страницы
The memory history mode doesn't assume a browser environment and therefore doesn't interact with the URL
const status = defineModel('status');
const statuses = [ 'all', 'alive', 'dead', 'unknown' ];
<select v-model="status">
<option v-for="n in statuses">{{ n }}</option>
</select>
defineProps({
data: {
type: Array,
default: () => [],
},
});
<div v-for="n in data">
<span :class="[ 'status', n.status ]"></span>
...
</div>
.status {
border-radius: 50%;
width: 30px;
height: 30px;
&.alive { background: green; }
&.dead { background: red; }
&.unknown { background: orange; }
}
const data = ref([ ... ]);
const status = ref('all');
const filteredData = computed(() => status.value === 'all'
? data.value
: data.value.filter(n => n.status === status.value)
);
<FilterBlock v-model:status="status" />
<CardList :data="filteredData" />
def unique_with_sum(arr, id_key, sum_key):
unique = {}
for n in arr:
unique.setdefault(n[id_key], { **n, sum_key: 0 })[sum_key] += n[sum_key]
return [*unique.values()]
result = unique_with_sum(arr, 'uid_1c', 'amount')
BREAKING: When used on custom components,v-model
prop and event default names are changed:
- prop:
value
->modelValue
;- event:
input
->update:modelValue
;
const getWeekdaysOfMonth = (year, month) =>
Array.from(
{ length: new Date(year, month, 0).getDate() },
function() {
this[0].setDate(-~this[0].getDate());
this[1] += this[0].getDay() === 1 || !this[1];
return `неделя ${this[1]}, ` + this[0].toLocaleString('ru-RU', {
day: 'numeric',
weekday: 'short',
});
},
[ new Date(year, ~-month, 0), 0 ]
);
const may2024 = getWeekdaysOfMonth(2024, 5);
const sep2023 = getWeekdaysOfMonth(2024, -3);
const jun2021 = getWeekdaysOfMonth(2020, 18);
unshift
, и ничего больше). Давайте закостылим - добавляем колонку, которая будет дублировать данный функционал, а оригинальную спрячем:const columns = [
...
{ name: 'selection' },
];
.xxx tr > :first-child {
display: none;
}
<q-table
...
table-class="xxx"
>
<template #header-cell-selection="props">
<q-th :props="props">
<q-checkbox v-model="props.selected" />
</q-th>
</template>
<template #body-cell-selection="props">
<q-td :props="props">
<q-checkbox v-model="props.selected" />
</q-td>
</template>
</q-table>