Files
front-end-example/07-vue2/08-components-communication-and-final/answer.js
charlie 3435848495 feat: add Vue2 exercises for dynamic styles, lifecycle methods, component communication, and course management dashboard
- Implement dynamic styles and event handling in Vue2 with a card component.
- Create lifecycle methods exercise to simulate async data loading and instance destruction.
- Develop a component communication exercise with props, events, and slots.
- Build a comprehensive course management dashboard with filtering, statistics, and component interactions.
2026-03-23 10:09:29 +08:00

81 lines
1.9 KiB
JavaScript

Vue.component("course-badge", {
props: {
label: {
type: String,
default: "默认角标",
},
},
template: `<span style="display:inline-block;margin-bottom:8px;padding:4px 10px;border-radius:999px;background:#eef4ff;color:#2d6cdf;">{{ label }}</span>`,
});
const CourseCard = {
props: {
course: {
type: Object,
required: true,
},
theme: {
type: String,
default: "normal",
validator(value) {
return ["normal", "accent"].includes(value);
},
},
},
template: `
<article class="card" :style="theme === 'accent' ? 'border-color:#2d6cdf;' : ''">
<course-badge :label="course.level"></course-badge>
<h2>{{ course.title }}</h2>
<p :class="{ done: course.finished }">
{{ course.finished ? "已完成" : "学习中" }}
</p>
<button type="button" @click="$emit('toggle', course.id)">
<slot name="action">操作</slot>
</button>
</article>
`,
};
new Vue({
el: "#app",
components: {
CourseCard,
},
data: {
keyword: "",
courses: [
{ id: 1, title: "Vue 实例", finished: true, level: "基础" },
{ id: 2, title: "模板语法", finished: false, level: "基础" },
{ id: 3, title: "组件通信", finished: false, level: "进阶" },
],
},
computed: {
filteredCourses() {
const value = this.keyword.trim().toLowerCase();
if (!value) {
return this.courses;
}
return this.courses.filter((course) => course.title.toLowerCase().includes(value));
},
},
methods: {
toggleCourse(courseId) {
this.courses = this.courses.map((course) => {
if (course.id === courseId) {
return {
...course,
finished: !course.finished,
};
}
return course;
});
},
focusInput() {
this.$refs.keywordInput.focus();
},
},
});