组件化编码流程(通用)
1.实现静态组件:抽取组件,使用组件实现静态页面的效果
结构
2.代码
1.App.vue
html
<template>
<div id="appContainer">
<TodoComponent/>
</div>
</template>
<script>
import TodoComponent from './components/TodoComponent.vue';
export default {
name: "App",
components: {
TodoComponent
}
};
</script>
<style>
#appContainer{
display: flex;
justify-content: center;
}
</style>
2.TodoComponent.vue
html
<template>
<div id="container">
<div id="parent">
<TodoHeader :addTodo="addTodo"/>
<TodoList :todos="todos" />
<TodoFooter :finish="finish" :all="all" :clear="clear" :doneAll="doneAll" />
</div>
</div>
</template>
<script>
import TodoFooter from "./TodoFooter.vue";
import TodoHeader from "./TodoHeader.vue";
import TodoList from "./TodoList.vue";
export default {
name: "TodoComponent",
components: {
TodoFooter,
TodoHeader,
TodoList,
},
data() {
return {
todos:[
{id:'001',title:'吃饭',done:true},
{id:'002',title:'睡觉',done:false},
{id:'003',title:'喝酒',done:true},
{id:'004',title:'开车',done:true},
{id:'005',title:'打游戏',done:false},
{id:'006',title:'随便',done:false},
{id:'007',title:'创业',done:false},
]
}
},
methods:{
addTodo(x){
console.log("我是Todo组件,我收到了数据",x);
this.todos.unshift(x);
},
clear(){
console.log('清除了');
const idList = this.todos.filter(x=>x.done).map(x=>x.id);
for(let i=0;i<this.todos.length;i++){
if(idList.includes(this.todos[i].id)){
this.todos.splice(i,1);
i--;
}
}
console.log(this.todos);
},
doneAll(choose){
this.todos.forEach(x=>x.done=choose)
}
},
computed:{
finish(){
return this.todos.filter(x=>x.done).length;
},
all(){
return this.todos.length;
}
}
};
</script>
<style scoped>
#parent {
width: 600px;
border: 1px solid #ccc;
display: flex;
justify-content: center; /* 水平居左 */
align-items: center; /* 垂直居中 */
flex-direction: column; /* 垂直排列子元素 */
}
#parent > *{
margin: 10px 0px;
}
</style>
3.TodoFooter.vue
html
<template>
<div id="container" v-show="all>0">
<div>
<input type="checkbox" v-model="allChoose" @change="doneAll(allChoose)"/>
<label>已完成{{finish}} / 全部{{all}}</label>
</div>
<button id="button" @click="clear">清除已完成的任务</button>
</div>
</template>
<script>
export default {
name: "TodoFooter",
data() {
return {
allChoose:false
}
},
updated() {
if(this.finish ===this.all && this.all > 0){
this.allChoose = true;
}else if(this.finish < this.all && this.all > 0){
this.allChoose = false;
}
//双向绑定可以绑定 计算属性 前提是计算属性要写 setter
},
props:['finish','all','clear','doneAll']
};
</script>
<style scoped>
#container {
display: flex;
justify-content: space-between; /* 水平居左 */
width: 500px;
height: 30px;
padding: 10px;
}
#container *{
padding: 5px;
}
#button {
width: 140px;
height: 28px;
color: white;
background-color: #eb1212;
border: 1px solid #ccc;
border-radius: 5px;
padding: 5px;
margin-right: 15px;
cursor: pointer; /* 鼠标悬停时显示手型光标 */
transition: background-color 0.3s ease; /* 平滑过渡 */
}
#button:hover {
background-color: #d10d0d; /* 鼠标悬停时颜色变化 */
}
#button:active {
background-color: #a00; /* 按下时颜色变化 */
transform: translateY(2px); /* 按下时按钮下移效果 */
}
</style>
4.TodoHeader.vue
html
<template>
<div>
<input
id="headerInput"
type="text"
placeholder="请输入你的任务名称,按回车键确认"
v-model="title"
@keyup.enter="submit"
/>
</div>
</template>
<script>
import { nanoid } from "nanoid"; //函数
export default {
name: "TodoHeader",
data() {
return {
title: "",
};
},
props: ["addTodo"],
methods: {
submit() {
//将用户的输入包装成一个todo对象
if (this.title.trim() === "") {
alert("输入不能为空");
return;
}
const todoObj = {
id: nanoid(),
title: this.title,
done: false,
};
this.addTodo(todoObj);
this.title = "";
//安装一些 nanoid npm i nanoid
},
},
};
</script>
<style scoped>
#headerInput {
width: 498px;
height: 30px;
border: 1px solid #ccc;
border-radius: 2px;
padding-left: 10px;
}
</style>
5.TodoItem.vue
html
<template>
<div id="container" @mouseover="handleMouseOver" @mouseleave="handleMouseLeave" >
<div id="d" >
<input type="checkbox" v-model="todo.done" />
<span @click="info">{{ todo.title }}</span>
</div>
<button id="button" v-show="showDelete" @click="deleteTodo">删除</button>
</div>
</template>
<script>
export default {
name: "TodoItem",
data() {
return {
todo: this.todoObj,
showDelete: false,
};
},
methods: {
info() {
console.log(this.todo);
},
handleMouseOver() {
this.showDelete = true;
},
handleMouseLeave() {
this.showDelete = false;
},
deleteTodo(){
this.removeTodo(this.todoObj.id)
}
},
props: {
todoObj: {
//传入的若是引用对象 则里面修改了,外面同样生效
type: Object,
required: true,
},
removeTodo:{
type:Function,
}
},
};
</script>
<style scoped>
#container:hover{
background-color: #a09a9a;
}
#container {
display: flex;
justify-content: space-between; /* 水平居左 */
align-items: center; /* 垂直居中 */
width: 500px;
height: 30px;
border: 0.1px solid #ccc;
border-radius: 2px;
padding-left: 10px;
padding-top: 5px;
padding-bottom: 5px;
}
#container * {
padding: 5px;
}
#button {
width: 50px;
height: 28px;
color: white;
background-color: #eb1212;
border: 1px solid #ccc;
border-radius: 5px;
padding: 5px;
margin-right: 15px;
cursor: pointer; /* 鼠标悬停时显示手型光标 */
transition: background-color 0.3s ease; /* 平滑过渡 */
}
#button:hover {
background-color: #d10d0d; /* 鼠标悬停时颜色变化 */
}
#button:active {
background-color: #a00; /* 按下时颜色变化 */
transform: translateY(2px); /* 按下时按钮下移效果 */
}
</style>
6. TodoList.vue
html
<template>
<div>
<TodoItem v-for="item in todosList" :key="item.id" :todoObj="item" :removeTodo="deleteTodo" />
</div>
</template>
<script>
import TodoItem from './TodoItem.vue'
export default {
name:'TodoList',
components:{
TodoItem
},
data() {
return {
todosList: this.todos
}
},
methods:{
deleteTodo(id){
for(var i=0;i<this.todosList.length;i++){
if(this.todosList[i].id===id){
console.log(i,"下标");
break;
}
}
this.todosList.splice(i,1);
}
},
props:['todos']
}
</script>
<style scoped>
</style>