Vue实现 TodoList
taotaoit Vue 2022-12-07 669 0
关于本站

“最难不过坚持”

本人承接扒站仿站,php网站维护,病毒查杀,网站编辑,网站改版,html制作

有需要网站维护,改版,病毒查杀,网站编辑,网站备案,html制作等相关的工作可以联系我。
本人有多年相关工作经验,也可提供免费咨询,交个朋友。
有需要探讨问题的朋友,也可以加我微信,共同探讨!
微信:15011482830 QQ:408917339

6279575 2594 39
最新评论
https://jueru.net/
评 留言
:weixiao:
评 留言
:shuijiao: :weiqu: :zhenbang: :leng:
评 留言
:yiwen: :yiwen: :yiwen: :yiwen:
评 EasySass: could not generate CSS file. See Output panel for details.
这个业务逻辑多少都有点奇怪了,阅读浏览次数增值在新闻详情页的控制器方法里setInc,这怎么还写进模型事件里了。如果非要用onAfterRead也可以,把新闻文章的内容单独分出来一个news_content表,然后把它和news做关联,然后给news_content表的onAfterRead事件做增值处理,这样点进新闻页内查询到文章内容时才会触发它。
评 TP6模型事件-查询后onAfterRead不好用
文章标签更多
ThinkPHP (254)
Mysql (58)
DedeCms (33)
jQuery (67)
证件照 (1)
setInc (4)
setDec (4)
onclick (5)
打开边栏(ESC) 关闭边栏(ESC)

案例的效果如下

 

一、组件化编码流程:
        (1).拆分静态组件:组件要按照功能点拆分,命名不要与html元素冲突。

        (2).实现动态组件:考虑好数据的存放位置,数据是一个组件在用,还是一些组件在用:

                1).一个组件在用:放在组件自身即可。

                2). 一些组件在用:放在他们共同的父组件上(状态提升)。

        (3).实现交互:从绑定事件开始。

拆分好的页面结构如下:

from clipboard

from clipboard

1,App组件

<template>
  <div id="app">
    <TodoHeader/>
    <TodoList :todos="todos"/>
    <TodoFooter :todos="todos"/>
  </div>
</template>

<script>
import pubsub from 'pubsub-js'

import TodoHeader from './components/TodoHeader.vue'
import TodoList from './components/TodoList.vue'
import TodoFooter from './components/TodoFooter.vue'

export default {
  name: 'App',
  components: {
    TodoHeader,TodoList,TodoFooter
  },
  data(){
    return{
      // todos:[
      //   {id:'001',title:'吃饭',done:true},
      //   {id:'002',title:'睡觉',done:false},
      //   {id:'003',title:'打豆豆',done:false},
      // ]
      todos:JSON.parse(localStorage.getItem('todos')) || []
    }
  },
  // 监视
  watch:{
    todos:{
      deep:true, // 深度监视
      handler(value){
        localStorage.setItem('todos',JSON.stringify(value))
      }
    }
  },
  methods: {
    // 添加任务
    addTodo(_,obj){
      this.todos.unshift(obj)
    },
    // 选中/取消
    checkTodo(_,id){
      this.todos.forEach((todo)=>{
        if(todo.id === id) todo.done = !todo.done
      })
    },
    // 删除
    deleteTodo(_,id){
      this.todos = this.todos.filter((todo)=>{
        return todo.id != id
      })
    },
    // 修改
    updateTodo(_,data){
      // console.log('updateTodo:',data.title);
      this.todos.forEach((todo)=>{
        if(todo.id == data.id) todo.title = data.title
      })
    },
    // 清除已完成
    clearAllTodo(){
      this.todos = this.todos.filter((todo)=>{
        return !todo.done
      })
    },
    // 全选
    checkAllTodo(_,done){
      this.todos.forEach((todo)=>{
        todo.done = done
      })
    }
  },
  // 挂载
  mounted() {
    // 消息订阅与发布-订阅
    this.addTodoId = pubsub.subscribe('addTodo',this.addTodo)
    this.checkTodoId = pubsub.subscribe('checkTodo',this.checkTodo)
    this.deleteTodoId = pubsub.subscribe('deleteTodo',this.deleteTodo)
    this.updateTodoId = pubsub.subscribe('updateTodo',this.updateTodo)
    this.clearAllTodoId = pubsub.subscribe('clearAllTodo',this.clearAllTodo)
    this.checkAllTodoId = pubsub.subscribe('checkAllTodo',this.checkAllTodo)
  },
  // 销毁前
  beforeDestroy() {
    pubsub.unsubscribe(this.addTodoId)
    pubsub.unsubscribe(this.checkTodoId)
    pubsub.unsubscribe(this.deleteTodoId)
    pubsub.unsubscribe(this.updateTodoId)
    pubsub.unsubscribe(this.clearAllTodoId)
    pubsub.unsubscribe(this.checkAllTodoId)
  },
}
</script>

<style>

</style>
2,TodoHeader组件
<template>
  <div>
    <input type="text" @keyup.enter="add">
  </div>
</template>

<script>
import {nanoid} from 'nanoid'
import pubsub from 'pubsub-js'
export default {
  name:'TodoHeader',
  methods: {
    add(e){
      if(!e.target.value.trim()) return alert('输入不能为空')
      const todoObj = {id:nanoid(),title:e.target.value,done:false}
      // console.log(todoObj);
      // 消息订阅与发布-发布
      pubsub.publish('addTodo',todoObj)
      e.target.value = ''
    }
  },
}
</script>

<style>

</style>
3,TodoList组件
<template>
  <div>
    <ul>
      <TodoItem v-for="todo in todos" :key="todo.id" :todo="todo"/>
    </ul>
  </div>
</template>

<script>
import TodoItem from './TodoItem.vue'
export default {
  name:'TodoList',
  components:{
    TodoItem
  },
  props:['todos']
}
</script>

<style>

</style>
4,TodoItem组件
<template>
  <li>
    <input type="checkbox" :checked="todo.done" @change="handleCheck(todo.id)">
    <span v-show="!todo.isEdit">{{todo.title}}</span>
    <input type="text" v-show="todo.isEdit" :value="todo.title" @blur="handleBlur(todo,$event)" ref="inputTitle">
    <button v-show="!todo.isEdit" @click="handleEdit(todo)">编辑</button>
    <button @click="handleDelete(todo.id)">删除</button>
  </li>
</template>

<script>
import pubsub from 'pubsub-js'
export default {
  name:'TodoItem',
  props:['todo'],
  methods: {
    // 选中/取消
    handleCheck(id){
      pubsub.publish('checkTodo',id)
    },
    // 删除
    handleDelete(id){
      pubsub.publish('deleteTodo',id)
    },
    // 编辑
    handleEdit(todo){
      // 判断是否保护isEdit属性
      if(todo.hasOwnProperty('isEdit')){
        todo.isEdit = true
      }else{
        this.$set(todo,'isEdit',true)
      }
      
      // 点击编辑按钮,输入框自动获得焦点
      this.$nextTick(function(){
        this.$refs.inputTitle.focus()
      })
    },
    // 失去焦点,提交修改
    handleBlur(todo,e){
      // 编辑状态改为false
      todo.isEdit = false
      if(!e.target.value.trim()) return alert('输入不能为空')
      // console.log(e.target.value);
      pubsub.publish('updateTodo',{id:todo.id,title:e.target.value})
    }
  },
}
</script>

<style scoped>
  button{
    display: none;
  }
  li:hover{
    background: #eee;
  }
  li:hover button{
    display: inline;  
  }
</style>
5,TotoFooter组件
<template>
  <div v-show="total">
    <!-- 方式一 -->
    <!-- <input type="checkbox" :checked="isAll" @change="checkAll"> -->
    <!-- 方式二 -->
    <input type="checkbox" v-model="isAll">
    已完成{{doneTotal}} / 全部 {{total}}
    <button @click="clearAll">清除已完成</button>
  </div>
</template>

<script>
import pubsub from 'pubsub-js'
export default {
  name:'TodoFooter',
  props:['todos'],
  computed:{
    total(){
      return this.todos.length
    },
    doneTotal(){
      return this.todos.reduce((pre,todo)=>{
        return pre + (todo.done ? 1 : 0)
      },0)
    },
    isAll:{
      get(){
        return this.total === this.doneTotal
      },
      set(value){
        pubsub.publish('checkAllTodo',value)
      }
    }
  },
  methods:{
    clearAll(){
      // 消息订阅与发布-发布
      pubsub.publish('clearAllTodo')
    },
    checkAll(e){
      pubsub.publish('checkAllTodo',e.target.checked)
    }
  }
}
</script>

<style>

</style>

其他:

1,nanoid生成唯一id

安装:

npm i nanoid

使用:

import { nanoid } from 'nanoid';  
let id = nanoid()
2,pubsub-js消息订阅与发布

安装:

npm i pubsub-js

使用:

import PubSub from 'pubsub-js'
// 发布消息
PubSub.publish('msg', data)
// 订阅消息
PubSub.subscribe('msg', function(msg, data){})

3,本地存储

Window.sessionStorage--存储的内容会随着浏览器窗口关闭而消失
Window.localStorage --存储的内容,需要手动清除才会消失。

以上两种存储方式,它们的API是完全相同的。主要区别就在是否是会存储到本地。相关API如下:

        ☆添加:xxxxxStorage.setItem('key', 'value');
        ☆获取:xxxxxStorage.getItem('person');
        ☆删除:xxxxxStorage.removeItem('key');
        ☆清空:xxxxxStorage.clear()

        在必要的时候搭配JSON.stringify和JSON.parse方法使用。

   注意:xxxxxStorage.getItem(xxx) 如果xxx对应的value获取不到,那么getItem的返回值是null。JSON.parse(null)的结果依然是null。

版权声明:本站原创文章,允许自由转载。

相关推荐
接口返回request failed with status code 500错误
Vue | 2023-02-20 2568
接口返回request failed with status code 500错误 登录界面,验证账号密码成功,但是返回500错误 可能原因:linux服务器,用tp5搭建的后台及接口,会生成一部分缓存文件,但是linux默认没有权限创建数据,所以,只要在缓存文件夹runtime添加写的权限即可
vue项目npm run serve默认浏览器打开
Vue | 2022-11-16 1839
1、在vue项目中,输入命令行  npm run serve   浏览器实现自动打开功能,需要添加 在配置文件(package.json)中添加 --open 2、浏览器自动打开后,可能会出现网址0.0.0.0:8080页面错误,见图 3、解决方法: 在--open后面再加上--...
评论:0条
评论加载中...
发表评论