Todo-List案例版本五

news2024/9/22 13:30:08

安装库npm i pubsub-js 

消息的订阅与发布

src/App.vue

<template>
    <div class="app">
        <h1>{{ msg }}</h1>
        <School/>
        <Student/>
    </div>
</template>

<script>
import Student from './components/Student'
import School from './components/School'

export default {
    name: 'App',
    data() {
        return {
            msg: '你好啊!'
        }
    },
    components: { Student, School }
}
</script>

<style scoped>
.app {
    background-color: gray;
    padding: 5px;
}
</style>

src/components/School.vue

<template>
    <div class="school">
        <h2>学校名称:{{ name}}</h2>
        <h2>学校地址:{{ address }}</h2>
    </div>
</template>

<script>
import pubsub from 'pubsub-js'
export default {
    name: 'School',
    data() {
        return {
            name:'黑马',
            address:'广州'
        }
    },
    methods:{
        demo(msgName,data){
            console.log('有人发布了hello消息,hello消息的回调执行了',msgName,data);
            console.log(this);// VueComponent
        }
    },
    mounted(){
        /* this.$bus.$on('hello',(data)=>{
            console.log('我是School组件,收到了数据',data);
        }) */

        /* this.pubId=pubsub.subscribe('hello',function(msgName,data){
            console.log('有人发布了hello消息,hello消息的回调执行了',msgName,data);
            console.log(this);// undefined
        }) */

        this.pubId=pubsub.subscribe('hello',this.demo)
    },
    beforeDestroy(){
        // this.$bus.$off('hello')
        pubsub.unsubscribe(pubId);
    }
}
</script>

<style scoped>
    .school{
        background-color: skyblue;
        padding: 5px;
    }
</style>

src/components/Student.vue

<template>
    <div class="student">
        <h2>学生姓名:{{ name }}</h2>
        <h2>学生性别:{{ sex }}</h2>
        <button @click="sendStudentName">发送学生名字到学校</button>
    </div>
</template>

<script>
import pubsub from 'pubsub-js'
export default {
    name: 'Student',
    data() {
        return {
            name:'张三',
            sex:'男'
        }
    },
    methods:{
        sendStudentName(){
            // this.$bus.$emit('hello',this.name)
            pubsub.publish('hello',666)
        }
    }
}
</script>

<style lang="less">
    .student{
        background-color: pink;
        padding: 5px;
        margin-top: 30px;
    }
</style>

src/main.js

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

// Vue.prototype.x={a:1,b:2}

//创建vm
new Vue({
    el: '#app',
    render: h => h(App)
})

$nextTick(回调函数) 

Todo-List最终完成版

hasOwnProperty和$set()和函数(参数,$event)使用

(161条消息) Todo-List案例版本四_bubbleJessica的博客-CSDN博客

src/components/MyHeader.vue

<template>
    <div class="todo-header">
        <input type="text" placeholder="请输入你的任务名称,按回车键确认" v-model="title" @keyup.enter="add()" />
    </div>
</template>

<script>
import {nanoid} from 'nanoid'
export default {
    name: 'MyHeader',
    data(){
        return{
            title:''
        }
    },
    // props:['addToDo'],
    methods:{
        add(){
            if(!this.title.trim()) return alert('输入不能为空!')
            // 给用户输入的内容包装成一个todoObj对象
            const todoObj={id:nanoid(),title:this.title,done:false};
            // this.addToDo(todoObj);
            this.$emit('addToDo',todoObj)
            this.title='';
        }
    }
}
</script>

<style scoped>
/*header*/
.todo-header input {
    width: 560px;
    height: 28px;
    font-size: 14px;
    border: 1px solid #ccc;
    border-radius: 4px;
    padding: 4px 7px;
}

.todo-header input:focus {
    outline: none;
    border-color: rgba(82, 168, 236, 0.8);
    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
}
</style>

src/components/MyList.vue

<template>
    <ul class="todo-main">
        <MyItem
             v-for="todoObj in todos" 
             :key="todoObj.id" 
             :todo="todoObj" 
        />
    </ul>
</template>

<script>
import MyItem from './MyItem.vue'

export default {
    name: 'MyList',
    props:['todos'],
    components: { MyItem }
}
</script>

<style scoped>
/*main*/
.todo-main {
    margin-left: 0px;
    border: 1px solid #ddd;
    border-radius: 2px;
    padding: 0px;
}

.todo-empty {
    height: 40px;
    line-height: 40px;
    border: 1px solid #ddd;
    border-radius: 2px;
    padding-left: 5px;
    margin-top: 10px;
}
</style>

src/components/MyItem.vue

<template>
    <li>
        <label>
            <input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)" />
            <!-- 以下代码也能实现功能,但是不太推荐,因为有点违反规则,因为修改了props,只不过vue没有监测到(vue监测到的情况是对象全部被变化 -->
            <!-- <input type="checkbox" v-model="todo.done"/> -->
            <span v-show="!todo.isEdit">{{ todo.title }}</span>
            <input 
                v-show="todo.isEdit"
                type="text" 
                :value="todo.title"
                @blur="handleBlur(todo,$event)"
                ref="inputTitle"
            >
        </label>
        <button class="btn btn-danger" @click="handleDelete(todo.id)">删除</button>
        <button v-show="!todo.isEdit" class="btn btn-edit" @click="handleEdit(todo)">编辑</button>
    </li>
</template>

<script>
import pubsub from 'pubsub-js'
export default {
    name: 'MyItem',
    //声明接收todo对象
    props: ['todo'],
    methods: {
        // 勾选或者取消勾选
        handleCheck(id) {
            // 通知App组件将对应的todo对象的done值取反
            // console.log(id);
            // this.checkTodo(id)
            this.$bus.$emit('checkTodo',id)
        },
        // 删除
        handleDelete(id){
            if(confirm('确定删除吗?')){
                // this.deleteTodo(id)  //事件名 自定义事件
                // this.$bus.$emit('deleteTodo',id) //事件名 全局事件总线

                pubsub.publish('deleteTodo',id) //消息名                
            }     
        },
        // 编辑
        handleEdit(todo){
            if(todo.hasOwnProperty('isEdit')){
                todo.isEdit=true
            }else{
                this.$set(todo,'isEdit',true)
            }
            // console.log(todo);
            // 作用:等上面所有逻辑执行完模板渲染完成之后,再执行下面的函数
            this.$nextTick(function(){
                this.$refs.inputTitle.focus()
            })
        },
        // 失去焦点回调,(真正执行修改逻辑)
        handleBlur(todo,e){
            todo.isEdit=false
            if(!e.target.value.trim()) return alert('输入不能为空!')
            // console.log('updateTodo',todo.id,e.target.value);
            this.$bus.$emit('updateTodo',todo.id,e.target.value)
        }
    }
}
</script>

<style scoped>
/*item*/
li {
    list-style: none;
    height: 36px;
    line-height: 36px;
    padding: 0 5px;
    border-bottom: 1px solid #ddd;
}

li label {
    float: left;
    cursor: pointer;
}

li label li input {
    vertical-align: middle;
    margin-right: 6px;
    position: relative;
    top: -1px;
}

li button {
    float: right;
    display: none;
    margin-top: 3px;
}

li:before {
    content: initial;
}

li:last-child {
    border-bottom: none;
}

li:hover {
    background-color: #ddd;
}

li:hover button {
    display: block;
}
</style>

src/components/MyFooter.vue

<template>
    <div class="todo-footer" v-show="total">
        <label>
            <!-- <input type="checkbox" :checked="isAll" @change="checkAll"/> -->
            <input type="checkbox" v-model="isAll"/>
        </label>
        <span>
            <span>已完成{{ doneTotal }}</span> / 全部{{ total }}
        </span>
        <button class="btn btn-danger" @click="clearAll">清除已完成任务</button>
    </div>
</template>

<script>
export default {
    name: 'MyFooter',
    // props: ['todos','checkAllTodo','clearAllTodo'],
    props: ['todos'],
    computed: {
        total() {
            return this.todos.length
        },
        doneTotal() {
            // 数组.reduce()方法
            // const x = this.todos.reduce((pre, cur) => {
            //     return pre + (cur.done ? 1 : 0)
            // }, 0)
            // return x
            return this.todos.reduce((pre, todo) => pre + (todo.done ? 1 : 0), 0)
        },
        // 计算属性简写版
        // isAll() {
        //     return this.doneTotal === this.total && this.total > 0
        // }

        // 计算属性完整版
        isAll:{
            get(){
                return this.doneTotal === this.total && this.total > 0
            },
            set(value){
                // this.checkAllTodo(value);
                this.$emit('checkAllTodo',value)
            }
        }
    },
    // methods:{
    //     checkAll(e){
    //         // console.log(e.target.checked);
    //         this.checkAllTodo(e.target.checked);
    //     }
    // }
    methods:{
        clearAll(){
            // this.clearAllTodo()
            this.$emit('clearAllTodo')
        }
    }
}
</script>

<style scoped>
/*footer*/
.todo-footer {
    height: 40px;
    line-height: 40px;
    padding-left: 6px;
    margin-top: 5px;
}

.todo-footer label {
    display: inline-block;
    margin-right: 20px;
    cursor: pointer;
}

.todo-footer label input {
    position: relative;
    top: -1px;
    vertical-align: middle;
    margin-right: 5px;
}

.todo-footer button {
    float: right;
    margin-top: 5px;
}
</style>

src/App.vue

<template>
    <div id="root">
        <div class="todo-container">
            <div class="todo-wrap">
                <MyHeader @addToDo="addToDo" />
                <MyList :todos="todos" />
                <MyFooter :todos="todos" @checkAllTodo="checkAllTodo" @clearAllTodo="clearAllTodo" />
            </div>
        </div>
    </div>
</template>

<script>
import pubsub from 'pubsub-js'
import MyHeader from './components/MyHeader'
import MyList from './components/MyList'
import MyFooter from './components/MyFooter'

export default {
    name: 'App',
    data() {
        return {
            // 由于todos是MyHeader组件和MyFooter组件都在使用,所以放在App中(状态提升)
            todos: JSON.parse(localStorage.getItem('todos')) || []
        }
    },
    components: { MyHeader, MyList, MyFooter },
    methods: {
        // 添加一个todo
        addToDo(todoObj) {
            this.todos.unshift(todoObj)
        },
        // 勾选or取消勾选一个todo
        checkTodo(id) {
            this.todos.forEach((todo) => {
                if (todo.id === id) todo.done = !todo.done
            })
        },
        // 更新一个todo
        updateTodo(id,title) {
            this.todos.forEach((todo) => {
                if (todo.id === id) todo.title = title
            })
        },
        // 删除一个todo
        deleteTodo(_,id) {
            // 注意:filter不改变原数组,只是新建一个数组
            this.todos = this.todos.filter((todo) => {
                return todo.id !== id
            })
        },
        // 全选or取消全选
        checkAllTodo(done) {
            this.todos.forEach((todo) => {
                todo.done = done
            })
        },
        // 清除所有已完成的todo
        clearAllTodo() {
            this.todos = this.todos.filter((todo) => {
                return !todo.done
            })
        }
    },
    watch: {
        // todos简写不包含深度监视
        // todos(value) {
        //     localStorage.setItem('todos', JSON.stringify(value))
        // }

        // todos完整版深度监视
        todos:{
            deep:true,
            handler(value){
                localStorage.setItem('todos', JSON.stringify(value))
            }
        }
    },
    mounted(){
        this.$bus.$on('checkTodo',this.checkTodo)
        this.$bus.$on('updateTodo',this.updateTodo)
        // this.$bus.$on('deleteTodo',this.deleteTodo)
        this.pubId=pubsub.subscribe('deleteTodo',this.deleteTodo)
    },
    beforeDestroy() {
        this.$bus.$off('checkTodo')
        this.$bus.$off('updateTodo')
        // this.$bus.$off('deleteTodo')
        pubsub.unsubscribe(this.pubId)
    },
}
</script>

<style>
/*base*/
body {
    background: #fff;
}

.btn {
    display: inline-block;
    padding: 4px 12px;
    margin-bottom: 0;
    font-size: 14px;
    line-height: 20px;
    text-align: center;
    vertical-align: middle;
    cursor: pointer;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
    border-radius: 4px;
}

.btn-danger {
    color: #fff;
    background-color: #da4f49;
    border: 1px solid #bd362f;
}

.btn-edit {
    color: #fff;
    background-color: skyblue;
    border: 1px solid rgb(182, 223, 240);
    margin-right: 5px;
}

.btn-danger:hover {
    color: #fff;
    background-color: #bd362f;
}

.btn:focus {
    outline: none;
}

.todo-container {
    width: 600px;
    margin: 0 auto;
}

.todo-container .todo-wrap {
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 5px;
}
</style>

src/main.js

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

//创建vm
new Vue({
    el: '#app',
    render: h => h(App),
    beforeCreate(){
        Vue.prototype.$bus=this //安装全局事件总线
    }
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/739941.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微信小程序常用组件的简单使用 view,scroll-view,swiper,swiper-item,text,rich-text,button,image

微信小程序常用组件的简单使用 1. view组件2. scroll-view 组件3. swiper 和 swiper-item 组件3.1. swiper组件中的常用属性 4. text 和 rich-text组件4.1. text组件4.2. rich-text 组件 5. button 组件6. image组件6.1. image的mode属性 1. view组件 view组件就类似于html中的…

问题总结(持续更新,欢迎补充)

文章目录 前言webshell流量特征内存马蜜罐应急响应Windows 事件ID如何是误报还是攻击&#xff08;如何判断是否攻击成功&#xff09;研判的思路渗透测试思路内网渗透相关溯源反制反序列化&#xff08;Shiro、Weblogic、Log4j&#xff09;CDNMySQL5.5版本以上和以下读写权限的区…

linux 系统errno 对应参考及代码

结论 linux下系统errno都有对应的说明描述&#xff0c;发生错误时获取errno即可知道具体问题描述 如下图 代码如下 golang版 package main import ("syscall""strings""fmt" ) func main() {for i : 0; i < 200; i {if !strings.HasPrefi…

【开源项目】自动化运维平台spug

Spug 基本介绍 Spug是面向中小型企业设计的轻量级无Agent的自动化运维平台&#xff0c;整合了主机管理、主机批量执行、主机在线终端、应用发布部署、在线任务计划、配置中心、监控、报警等一系列功能。 批量执行: 主机命令在线批量执行在线终端: 主机支持浏览器在线终端登录…

为什么技术牛逼的人,不能直接提为项目经理?

早上好&#xff0c;我是老原。 很多来私信我职业规划的小友&#xff0c;有很大一部分都是从事了大几年&#xff0c;10年的技术开发大佬…… 到这个层级的大佬&#xff0c;他们最大的困惑是&#xff1a;到我这个年纪/级别还有必要转管理吗&#xff1f; 是否有必要&#xff0c…

X6 基于VUE流程编辑器开发

先看效果图 主要插件X6 x6-vue-shape antv/x6-plugin-dnd 代码太多没有整理出来

个人云服务器搭建MQTT服务器

个人云服务器搭建MQTT服务器 文章目录 个人云服务器搭建MQTT服务器1️⃣ 前言2️⃣ EMQX部署 1️⃣ 前言 MQTT &#x1f449;MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;即消息队列遥测传输协议 • 是一个轻量的发布订阅模式消息传输协议&#xff0c;专门…

leetcode140. 单词拆分 II 记忆化DFS

https://leetcode.cn/problems/word-break-ii 给定一个字符串 s 和一个字符串字典 wordDict &#xff0c;在字符串 s 中增加空格来构建一个句子&#xff0c;使得句子中所有的单词都在词典中。以任意顺序 返回所有这些可能的句子。 注意&#xff1a;词典中的同一个单词可能在分…

趣谈拜占庭将军问题

拜占庭将军问题&#xff08;The Byzantine Generals Problem&#xff09;&#xff0c;它其实是借拜占庭将军的故事展现了分布式共识问题&#xff0c;还探讨和论证了解决的办法。而大多数人觉得它难理解&#xff0c;除了因为分布式共识问题比较复杂之外&#xff0c;还与莱斯利兰…

【C++ OJ练习】6.验证回文串

1.题目链接 力扣 2.解题思路 字母全部要变成小写 并且不能管空格和标点 这样从前和后分别遍历并进行比较 如果遇到不是相同 字符的话 说明不是回文串 就这样一直往下走 直到最后两下标相遇 那么就是回文串 注意双循环条件 3.代码 class Solution { public://除去标点和空…

【如何在深度学习的道路上越走越远?——《深度学习模式与实践》】

作为近几年人工智能领域的主要研究方向之一&#xff0c;深度学习主要通过构建深度卷积神经网络和采用大量样本数据作为输入&#xff0c;最终得到一个具有强大分析能力和识别能力的模型。深度学习可以是有监督的、半监督的或无监督的。深度学习架构(例如深度神经网络、深度信念网…

Docker查看相关存储信息以及扩容

Docker查看相关存储信息以及扩容 &#xff08;mac环境&#xff09; 查看docker基本信息&#xff1a; docker info可以看到docker的存储位置在这里 2. 查看mac的所有盘以及分区大小情况 diskutil listdocker查看网络信息&#xff1a; docker ps # 查看所有在运行的container信…

Zabbix——监控模板

方法二&#xff1a;自定义监控模板 案例&#xff1a;自定义监控客户端服务器登录的人数 需求&#xff1a;监控客户端的登录人数&#xff0c;超过 3 个就发出报警信息 1&#xff09;在客户端创建自定义 key #在客户端创建自定义 key1.明确需要执行的 linux 命令who | wc -l​…

分类分级一小步,数据安全一大步

启明星辰集团凭借自身在数据安全治理管控的技术优势及各类数据安全治理项目的经验积累&#xff0c;以数据安全治理管控平台&#xff08;DSMP&#xff09;为基础&#xff0c;定制研发出数据分类分级系统&#xff0c;它是一款面向数据对象&#xff0c;可实现数据自动化分类分级的…

计算机视觉中的感受野

一、感受野的定义 感受野&#xff08; R e c e p t i v e Receptive Receptive F i e l d Field Field&#xff09;的定义是卷积神经网络每一层输出的特征图&#xff08; f e a t u r e feature feature m a p map map&#xff09;上的像素点在原始输入图片上映射的区域大小…

4.10 x64dbg 反汇编功能的封装

LyScript 插件提供的反汇编系列函数虽然能够实现基本的反汇编功能&#xff0c;但在实际使用中&#xff0c;可能会遇到一些更为复杂的需求&#xff0c;此时就需要根据自身需要进行二次开发&#xff0c;以实现更加高级的功能。本章将继续深入探索反汇编功能&#xff0c;并将介绍如…

redis缓存简介

1、为什么使用redis 分析:博主觉得在项目中使用redis&#xff0c;主要是从两个角度去考虑:性能和并发。当然&#xff0c;redis还具备可以做分布式锁等其他功能&#xff0c;但是如果只是为了分布式锁这些其他功能&#xff0c;完全还有其他中间件(如zookpeer等)代替&#xff0c;并…

中国地图数据可视化制作,python的pyecharts模块读取excel可视化,

数据格式如下&#xff1a; import pandas as pd from pyecharts import options as opts from pyecharts.charts import Map from pyecharts.globals import ChartType# 读取Excel数据 data pd.read_excel(C:\\Users\\Administrator\\Desktop\\国内数据.xlsx)# 创建地图实例 m…

C语言itoa转化为二进制

C语言itoa函数常常用于把整型转换为字符数组&#xff1b;最常用的是十进制的转换&#xff1b; 也可以用于获取一个数的二进制&#xff1b; 在C语言中 3&51&#xff1b;&是按位与&#xff1b; 先输出3&5&#xff1b; 再分别输出3和5的二进制看一下&#xff1b; …

Shader 基础之 Unity Shader概念

目录 目录 Shader compilation Conditionals in shaders Different types of conditionals Switch code branch at runtime Branching in shaders Static branching How to use static branching Dynamic branching How to use dynamic branching Shader variants …