через Vuex я уже сделал, теперь хочу потренироваться на шине событий
в чём моя ошибка понять не могу
Весь текст, как я понимаю, находится в js-файле.
<tr>
<tr>
...
<tr>
<tr v-for="n in data">
loadData() {
fetch(...).then(r => r.json()).then(r => this.data = r);
},
const sumNested = (data, getVal, key) => Object
.entries(data instanceof Object ? data : {})
.reduce((acc, [ k, v ]) => acc + sumNested(v, getVal, k), getVal(key, data));
const numItems = sumNested(obj, (k, v) => (k === 'items' && Array.isArray(v)) ? v.length : 0);
function sumNested(data, getVal) {
let result = 0;
for (const stack = [ [ , data ] ]; stack.length;) {
const [ k, v ] = stack.pop();
stack.push(...(v instanceof Object ? Object.entries(v) : []));
result += getVal(k, v);
}
return result;
}
methods: {
onFileChange(e) {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onloadend = () => {
const image = new Image();
image.onload = () => {
this.$emit('uploaded', {
file,
src: image.src,
});
};
image.src = reader.result;
};
reader.readAsDataURL(file);
}
},
},
<i
v-text="img.src ? 'x' : '+'"
@click="$emit('remove')"
...
/>
<img
v-if="img.src"
:src="img.src"
...
>
<input type="file" accept="image/*" @change="onFileChange">
v-model
. В props переименовываете images в value, убираете из дефолтного значения объект с пустыми полями. Добавляете images в computed - в качестве значения будет копия value плюс, если длина value меньше максимально допустимой, тот объект с пустыми полями; сеттер - отправляет родителю images, из которого выкинут пустой объект:props: {
value: Array,
max: {
type: Number,
default: 3,
},
},
computed: {
images: {
get() {
const images = [...this.value];
if (images.length < this.max) {
images.push({
file: null,
src: null,
});
}
return images;
},
set(val) {
this.$emit('input', val.filter(n => n.file));
},
},
},
methods: {
onUpload(index, img) {
this.images = this.images.map((n, i) => i !== index ? n : img);
},
remove(index) {
this.images = this.images.filter((n, i) => i !== index);
},
},
<input-img
v-for="(n, i) in images"
:img="n"
@uploaded="onUpload(i, $event)"
@remove="remove(i)"
/>
data: () => ({
images: [],
}),
<set-imgs v-model="images" :max="5" />
final_data.reduce((acc1, num1) => acc1.reduce((acc2, num2) => acc2.concat(num1.map(num3 => [].concat(num2, num3))), []))
final_data.reduce((acc1, num1) => {
return acc1.reduce((acc2, num2) => {
acc2.push(...num1.map(num3 => [...num2, ...num3]));
return acc2;
}, [])
})
return final_data.reduce((acc1, num1) =>
acc1.reduce((acc2, num2) => (
acc2.push(...num1.map(num3 => num2 + num3)),
acc2
), [])
).join(',');
const whatIsInAName = (collection, source) =>
collection.filter(function(n) {
return this.every(([ k, v ]) => n[k] === v);
}, Object.entries(source));
function whatIsInAName(collection, source) {
const result = [];
COLLECT:
for (const n of collection) {
for (const k in source) {
if (n[k] !== source[k]) {
continue COLLECT;
}
}
result.push(n);
}
return result;
}
const parentSelector = '.wrap';
const wrapperTag = 'div';
const wrapperClass = 'wrap-item';
const wrapSize = 4;
const $items = $(parentSelector).children();
for (let i = 0; i < $items.length; i += wrapSize) {
$items.slice(i, i + wrapSize).wrapAll(`<${wrapperTag} class="${wrapperClass}">`);
}
const parent = document.querySelector(parentSelector);
parent.append(...Array.from(
{ length: Math.ceil(parent.children.length / wrapSize) },
() => {
const wrapper = document.createElement(wrapperTag);
wrapper.classList.add(wrapperClass);
wrapper.append(...Array.prototype.slice.call(parent.children, 0, wrapSize));
return wrapper;
}
));
const text = document.querySelector('#area').value;
const pre = document.querySelector('#pre');
pre.innerHTML = text.replace(/f+/g, '<span>$&</span>');
document.addEventListener('scroll', function() {
document.querySelector('.wrap_portfolio').style.transform = `translateX(${window.scrollY}px)`;
});
const color = 'orange';
.const { id = null } = Object.values(fruits).find(n => n.color === color) || {};
// или
let id = null;
for (const k in fruits) {
if (fruits.hasOwnProperty(k) && fruits[k].color === color) {
id = fruits[k].id;
break;
}
}
А если у меня несколько оранжевых фруктов, как поступить?
const ids = Object.values(fruits).reduce((acc, n) => (
n.color === color && acc.push(n.id),
acc
), []);
function group(data, key, val = n => n) {
const getKey = key instanceof Function ? key : n => n[key];
const getVal = val instanceof Function ? val : n => n[val];
const result = {};
for (const n of data) {
const k = getKey(n);
(result[k] = result[k] || []).push(getVal(n));
}
return result;
}
const idsByColor = group(Object.values(fruits), 'color', 'id');
const orangeIds = idsByColor.orange || [];
const greenIds = idsByColor.green || [];
state = {
block1: false,
block2: false,
}
componentDidMount() {
setTimeout(() => this.setState({ block1: true }), 3000);
setTimeout(() => this.setState({ block2: true }), 6000);
}
render() {
const { block1, block2 } = this.state;
return (
...
{block1 && <div class="block-1">Блок 1</div>}
{block2 && <div class="block-2">Блок 2</div>}
...
);
}
<div id="app">
<todo-add @todo-new="addNewTodo"></todo-add>
<pre>{{ todoJson }}</pre>
</div>
Vue.component('todo-add', {
template: `
<div>
<input v-model="name" autofocus></input>
<button @click="add">Add New Todo</button>
</div>`,
data: () => ({
name: '',
}),
methods: {
add() {
const name = this.name.trim();
if (name) {
this.$emit('todo-new', name);
this.name = '';
}
},
},
});
new Vue({
el: '#app',
data: {
todoArr: [
{ id: 1, name: 'hello, world!!' },
],
},
methods: {
addNewTodo(name) {
this.todoArr.push({
id: 1 + Math.max(0, ...this.todoArr.map(n => n.id)),
name,
});
},
},
computed: {
todoJson() {
return JSON.stringify(this.todoArr, null, 2);
},
},
});
id="0"
---> data-index="0"
.const imgSelector = '#main__display img';
const key = 'index';
const attr = `data-${key}`;
const buttonSelector = `[${attr}]`;
const getSrc = el => collect[
$(el).data(key)
// или
$(el).attr(attr)
// или
el.dataset[key]
// или
el.getAttribute(attr)
// или
el.attributes[attr].value
];
$(buttonSelector).click(function(e) {
$(imgSelector).attr('src', getSrc(this));
});
// или
$(document).on('click', buttonSelector, e => {
$(imgSelector).prop('src', getSrc(e.currentTarget));
});
// или
document.querySelectorAll(buttonSelector).forEach(function(n) {
n.addEventListener('click', this);
}, function(e) {
this.setAttribute('src', getSrc(e.currentTarget));
}.bind(document.querySelector(imgSelector)));
// или
document.addEventListener('click', ({ target: t }) => {
if (t = t.closest(buttonSelector)) {
document.querySelector(imgSelector).src = getSrc(t);
}
});