Vue Events - Не удается прослушать событие $ emit от дочернего компонента - PullRequest
0 голосов
/ 17 февраля 2019

У меня простая проблема, я просто не могу понять, почему она не работает.У меня есть дочерний компонент «кнопки приложения», где у меня есть поле ввода, которое я хочу прослушать, чтобы я мог отфильтровать список на основе значения ввода.

Если я поместил ввод в коренькомпонент, где у меня есть список, все работает хорошо.Но я хочу разделить его на $ emit и найти входное значение для поиска, затем использовать его.

// THIS IS THE COMPONENT WHERE I WAN'T TO LISTEN TO THE SEARCH INPUT

import Buttons from './app-buttons.js';
import Event from './vue-event.js';

export default Vue.component('post-item', {

	template: `
		<section class="posts flex" v-if="posts">
			<app-buttons :posts="posts"></app-buttons>

			<transition-group name="posts" tag="section" class="posts flex">
				<article class="postitem" :class="{ 'danger': !post.published }" v-for="post in posts" :key="post.id">
					<p v-if="post.published">Post is published</p>
					<p v-else>Post is <em><strong>not</strong></em> published</p>
					<h4>{{ post.title }}</h4>

					<button type="submit" @click="post.published = !post.published">Change status</button>
				</article>
			</transition-group>
		</section>
	`,

	data() {
		return {
		};
	},

	components: {
		Buttons,
	},

	props: {
		posts: Array,
		filterdList: [],
	},

	created() {
		console.log('%c Post items', 'font-weight: bold;color:blue;', 'created');
	},

	computed: {
		//filteredList() {
		//	return this.posts.filter(post => {
		//		return post.title.toLowerCase().includes(this.search.toLowerCase());
		//	});
		//},
	},

	methods: {
		update() {
			console.log('test');
		}
	}
});





// THIS IS THE COMPONENT IM TRIGGERING THE $EVENT FROM

import Event from './vue-event.js';

export default Vue.component('app-buttons', {
	template: `
		<div class="postswrapper flex flex--center flex--column">

			<section :class="className" class="flex flex--center">
				<button type="button" @click="showUnpublished">Unpublish</button>
				<button type="button" @click="shufflePosts">Shuffle</button>
			</section>

			<section :class="className">
				<input type="text" v-model="search" v-on:input="updateValue" placeholder="Search..." />
			</section>

		</div>
	`,

	data() {
		return {
			className: 'buttons',
			search: '',
		}
	},

	props: {
		posts: Array,
	},

	created() {
		//console.log(this);
		console.log('%c Buttons', 'font-weight: bold;color:blue;', 'created');
	},

	methods: {
		updateValue() {
			//console.log(this.search);
			this.$emit('searchquery', this.search);
		},

		showUnpublished() {
			this.posts.forEach(item => {
				item.published = true;
			})
		},
 
		shufflePosts() {
			this.$emit('postshuffled', 'Fisher-Yates to the rescue');
			for (var i = this.posts.length - 1; i >= 0; i--) {
				let random = Math.floor(Math.random() * i);
				let temp = this.posts[i];
				
				Vue.set(this.posts, i, this.posts[random]);
				Vue.set(this.posts, random, temp);
			}
		},
	}
});
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Vue JS</title>
	
	<script src="https://cdn.jsdelivr.net/npm/vue@2.6.6/dist/vue.js"></script>
	<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>

	<div id="app">
		<app-header :logo="logo" :name="name"></app-header>
		<post-item :posts="posts" v-on:searchquery="update" v-on:sq="update" v-on:postshuffled="update"></post-item>
	</div>

	<script type="module">
		import AppHeader from './components/app-header.js';
		import PostItem from './components/post-item.js';

		const app = new Vue({
			el: '#app',
			data: {
				name: 'Vue App',
				logo: {
					class: 'vue-logo',
					src: 'https://vuejs.org/images/logo.png',
				},
				components: {
					AppHeader,
					PostItem,
				},
				posts: [
					{id: 1, title: 'Test', published: true},
					{id: 2, title: 'New post', published: true},
					{id: 3, title: 'Added', published: true},
					{id: 4, title: 'Another post', published: true},
					{id: 5, title: 'In the future', published: false},
					{id: 6, title: 'Last post', published: true},
				],
			},

			created() {
				console.log('Created');
			},

			mounted() {
				console.log('Mounted');
			},

			methods: {
				update() {
					console.log('updated');
				}
			},
		});
	</script>

</body>
</html>

Ответы [ 2 ]

0 голосов
/ 17 февраля 2019

Хорошо, я изменил разметку, и она работает.Но будет ли это лучшим способом сделать это?:) И спасибо Рою Дж за помощь.

import Event from './vue-event.js';
import Buttons from './app-buttons.js';

export default Vue.component('post-item', {

	template: `
		<section class="posts flex" v-if="posts">
			<app-buttons :posts="posts" v-on:searchquery="update($event)"></app-buttons>

			<transition-group name="posts" tag="section" class="posts flex">
				<article class="postitem" :class="{ 'danger': !post.published }" v-for="post in filteredItems" :key="post.id">
					<p v-if="post.published">Post is published</p>
					<p v-else>Post is <em><strong>not</strong></em> published</p>
					<h4>{{ post.title }}</h4>

					<button type="submit" @click="post.published = !post.published">Change status</button>
				</article>
			</transition-group>
		</section>
	`,

	data() {
		return {
			search: '',
		};
	},

	components: {
		Buttons,
	},

	props: {
		posts: Array,
	},

	created() {
		console.log('%c Post items', 'font-weight: bold;color:blue;', 'created');
	},

	computed: {
		filteredItems(search) {
			return this.posts.filter(post => {
				return post.title.toLowerCase().indexOf(this.search.toLowerCase()) > -1
			});
		}
	},

	methods: {
		update(event) {
			this.search = event;
		}
	}
});



// Child component
import Event from './vue-event.js';

export default Vue.component('app-buttons', {
	template: `
		<div class="postswrapper flex flex--center flex--column">

			<section :class="className" class="flex flex--center">
				<button type="button" @click="showUnpublished">Unpublish</button>
				<button type="button" @click="shufflePosts">Shuffle</button>
			</section>

			<section :class="className">
				<input type="text" v-model="search" v-on:input="updateValue" placeholder="Search..." />
			</section>

		</div>
	`,

	data() {
		return {
			className: 'buttons',
			search: '',
		}
	},

	props: {
		posts: Array,
	},

	created() {
		console.log('%c Buttons', 'font-weight: bold;color:blue;', 'created');
	},

	methods: {
		updateValue() {
			this.$emit('searchquery', this.search);
		},

		showUnpublished() {
			this.posts.forEach(item => {
				item.published = true;
			})
		},
 
		shufflePosts() {
			for (var i = this.posts.length - 1; i >= 0; i--) {
				let random = Math.floor(Math.random() * i);
				let temp = this.posts[i];
				
				Vue.set(this.posts, i, this.posts[random]);
				Vue.set(this.posts, random, temp);
			}
		},
	}
});
Index same as before, just without alle the events on the components.
0 голосов
/ 17 февраля 2019

Вы говорите:

У меня есть дочерний компонент "кнопки приложения", где у меня есть поле ввода, которое я хочу прослушать, поэтому я могу отфильтровать список на основе значения ввода.

У вас есть:

<div id="app">
    <app-header :logo="logo" :name="name"></app-header>
    <post-item :posts="posts" v-on:searchquery="update" v-on:sq="update" v-on:postshuffled="update"></post-item>
</div>

Это говорит о том, что вы ожидаете, что post-item издаст событие searchquery.Это не.

В пределах post-item у вас есть:

    <app-buttons :posts="posts"></app-buttons>

Таким образом, вы ожидаете, что app-buttons испустит событие и post-item неявно раздувает его, но события Vue не всплывают.Если вы хотите такое поведение, вам нужно будет post-item обработать событие:

    <app-buttons :posts="posts" v-on:searchquery="$emit('searchquery', $event)"></app-buttons>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...