v-model
.props: {
value: Number,
...
computed: {
item() {
return this.items[this.value];
},
...
<transition name="slide-fade" mode="out-in">
<div class="content" :key="value">
<h2>{{ item.title }}</h2>
<p>{{ item.text }}</p>
</div>
</transition>
methods: {
next(change) {
const len = this.items.length;
this.$emit('input', (this.value + change + len) % len);
},
...
<button @click="next(-1)">Prev</button>
<button @click="next(+1)">Next</button>
data: () => ({
active: 1,
...
<v-slider
v-model="active"
...
data: () => ({
items: [ 'hello, world!!', 'fuck the world', 'fuck everything' ],
focused: null,
}),
<div v-for="(n, i) in items">
<input @focus="focused = i" @blur="focused = null">
<span v-show="focused === i" v-text="n"></span>
</div>
('#app') new Vue({ router, store, render: h => h(App) }).$mount
data: () => ({
items: [
{ show: false, ... },
{ show: false, ... },
...
],
}),
computed: {
showItems() {
return this.items.filter(n => n.show);
},
},
mounted() {
this.items.forEach((n, i) => setTimeout(() => n.show = true, i * 1000));
},
<transition-group name="fade">
<div v-for="n in showItems" :key="n.id">{{ n }}</div>
</transition-group>
через Vuex я уже сделал, теперь хочу потренироваться на шине событий
в чём моя ошибка понять не могу
Весь текст, как я понимаю, находится в js-файле.
<tr>
<tr>
...
<tr>
<tr v-for="n in data">
loadData() {
fetch(...).then(r => r.json()).then(r => this.data = r);
},
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" />
<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);
},
},
});