效果概述
回车添加,删除,选中则禁用,过滤
具体效果
按回车键添加一层数据 按下拉箭头全部选中,全不选 选中则禁用 过滤全部,选中,未选中 全部删除 单个删除 双击改变名称
实现后效果图
todos 具体效果
具体代码思路
给 input 框绑定回车事件,回车后把数据请求到 vuex 中 把数据保存至本地存储中 给下拉箭头绑定点击事件,点击则给所有多选框进行反选 判断是否选中,如果选中则禁用 给数组进行过滤,然后渲染至页面中 双击 input 框 则允许改变样式,平时则禁止改变
HTML 结构
准备模拟数据,将数据添加到页面中,使用v-for;使用v-model实现数据的双向绑定
实现添加功能(在文本框输入,按回车添加数据)
编辑操作(双击每条信息todo,进行编辑)
双击todo时,给该条数据添加类editing,使得其进入编辑状态,并聚焦focus
编辑完成使用enter,改变该条数据
使用enter,退出编辑
失去焦点时退出编辑blur
删除(点击叉号时删除该条数据)
绑定一个点击事件
使用filter对todos进行操作
显示未完成的数量
计算出剩余未完成的数量
使用computed侦听属性,当checkbox变换时,进行侦听
不同按钮渲染不同数据
当点击按钮时,路由切换(改变路由)
点击All显示全部,点击Active显示已经完成的,Completed显示未完成的
如果绑定点击事件会比较麻烦,使用watch监听则刚进来时获取不到任何东西,所以只能使用计算属性(侦听的是自己的数据)
<div class="box"> <ul class="center"> <li>todos</li> <li> <input type="text" v-model="text" placeholder="What needs to be done?" @keyup.enter="submit" /> <span class="bottom" @click="AllChecked" v-show="Down">❯</span> </li> <li v-for="(item, index) in list" :key="index" @mouseover="mouseOver(item)" @mouseleave="mouseLeave(item)" > <input type="text" v-model="item.title" :disabled="item.disabled" :readonly="item.readonly" @dblclick="dbTest(index)" @keyup.enter="readonly(index)" /> <input type="checkbox" class="ckbox" v-model="item.checkbox" @click="radio(index)" /> <button class="delete" v-show="item.delete" @click="Delete(index)"> × </button> </li> <li v-show="Down"> <span> {{ id }} items left</span> <span v-for="(item, index) in tabs" :key="index" @click="Inquire(index)" :style="{ color: item.color }" > {{ item.title }} </span> <button @click="Clear">Clear completed</button> </li> </ul> </div>
CSS 样式
css 样式使用 scss
.box { width: 100%; height: 100vh; background-color: #f5f5f5; .center { width: 550px; margin: 0 auto; li { width: 100%; height: 65px; list-style: none; position: relative; input { width: 100%; height: 65px; border: none; padding: 20px 0px 20px 50px; border-bottom: 1px solid #ededed; outline: none; } button { background-color: rgba($color: #000000, $alpha: 0); border: none; color: #cc9a9a; font-size: 28px; margin-top: -8px; } .bottom { position: absolute; top: 18px; left: 15px; color: gainsboro; font-size: 25px; transform: rotate(90deg); } .ckbox { width: 20px; height: 20px; border-radius: 100%; position: absolute; top: 25px; left: 15px; } .delete { position: absolute; top: 25px; right: 15px; } } li:last-child { background-color: #fff; display: flex; justify-content: space-between; align-items: center; button { background-color: rgba($color: #000000, $alpha: 0); border: none; color: #000; font-size: 16px; margin: 0; } } li:first-child { height: 80px; text-align: center; line-height: 80px; font-size: 50px; color: rgba(175, 47, 47, 0.15); } li:nth-of-type(2) { input { // color: #e6e6e6; font-size: 25px; } } } }
JS 实现效果
import { mapState } from "vuex"; export default { data() { return { text: "", }; }, computed: { ...mapState(["list", "id", "all", "Down", "tabs"]), }, mounted() { this.$store.commit("refresh"); }, methods: { // 提交 submit() { if (this.text == "") { alert("不能为空"); } else { this.$store.commit("list", { checkbox: false, title: this.text, delete: false, disabled: false, readonly: true, }); this.text = ""; } }, // 鼠标移入 mouseOver(item) { item.delete = true; }, // 鼠标移出 mouseLeave(item) { item.delete = false; item.readonly = true; localStorage.setItem("lists", JSON.stringify(this.list)); }, // 删除 Delete(i) { this.$store.commit("Delete", i); }, // 全部删除 Clear() { this.$store.commit("clear"); }, // 全选 AllChecked() { this.$store.commit("AllChecked", this.all); }, // 单选 radio(i) { this.$store.commit("radio", i); }, // 查询 Inquire(index) { if (index == 0) { this.$store.commit("All"); } else if (index == 1) { this.$store.commit("Active"); } else { this.$store.commit("Completed"); } }, // 双击修改 dbTest(index) { this.$store.commit("dbTest", index); }, // 回车取消修改 readonly(index) { this.$store.commit("readonly", index); }, }, };
vuex 具体代码
使用Vuex:
如果不是大型单页应用,使用 Vuex 可能是繁琐冗余的。如果您的应用够简单,您最好不要使用 Vuex。这里我们是用来学习,所以使用一下vuex试试
import { createStore } from 'vuex' export default createStore({ state: { list:JSON.parse(localStorage.getItem("lists")) || [], id:'', all:false, Down: true, tabs: JSON.parse(localStorage.getItem("tab")) || [ { title: "All", tab: "all", color: "red" }, { title: "Active", tab: true, color: "black" }, { title: "Completed", tab: false, color: "black" }, ], }, getters: { }, mutations: { // 页面刷新时 refresh(state){ let arr1 = state.list.filter((item) => { return !item.checkbox; }); state.id = arr1.length if(state.list == ""){ state.Down = false }else{ state.Down = true } let arr = state.list.filter((item) => { return item.checkbox ; }); if(arr.length == state.list.length){ state.all = true }else{ state.all = false } }, // 添加 list(state,data){ state.list.push(data) localStorage.setItem('lists',JSON.stringify(state.list)) localStorage.removeItem('listd') this.commit('refresh') }, // 删除 Delete(state,data){ state.list.splice(data,1) localStorage.setItem('lists',JSON.stringify(state.list)) localStorage.removeItem('listd') this.commit('refresh') }, // 全部删除 clear(state){ state.list = '' // localStorage.setItem('lists',JSON.stringify(state.list)) localStorage.removeItem('lists') localStorage.removeItem('listd') state.id = 0 if(state.list == ""){ state.Down = false }else{ state.Down = true } }, // 全选 AllChecked(state,data){ console.log(!data); for(let i in state.list){ // console.log(state.list[i].checkbox = !data); state.list[i].checkbox = !data state.list[i].disabled = !data } state.all = !data localStorage.setItem('lists',JSON.stringify(state.list)) this.commit('refresh') }, // 单选 radio(state,data){ state.list[data].checkbox = !state.list[data].checkbox let arr = state.list.filter((item) => { return item.checkbox ,item.disabled = item.checkbox; }); if(arr.length == state.list.length){ state.all = true }else{ state.all = false } localStorage.setItem('lists',JSON.stringify(state.list)) this.commit('refresh') }, // 查询全部 All(state){ if(JSON.parse(localStorage.getItem("listd")) === null){ state.list = JSON.parse(localStorage.getItem("lists")) localStorage.setItem('lists',JSON.stringify(state.list)) }else{ state.list = JSON.parse(localStorage.getItem("listd")) localStorage.removeItem('listd') localStorage.setItem('lists',JSON.stringify(state.list)) } for (let i in state.tabs) { state.tabs[i].color = "black" } state.tabs[0].color = "red" localStorage.setItem('tab',JSON.stringify(state.tabs)) this.commit('refresh') }, // 查询未选中 Active(state){ if(JSON.parse(localStorage.getItem("listd")) === null){ let listd = state.list.filter((item) => { return !item.checkbox; }); localStorage.setItem('listd',JSON.stringify(state.list)) state.list = listd localStorage.setItem('lists',JSON.stringify(state.list)) }else{ let lists = JSON.parse(localStorage.getItem("listd")) let listd = lists.filter((item) => { return !item.checkbox; }); state.list = listd localStorage.setItem('lists',JSON.stringify(state.list)) } for (let i in state.tabs) { state.tabs[i].color = "black" } state.tabs[1].color = "red" localStorage.setItem('tab',JSON.stringify(state.tabs)) }, // 查询选中 Completed(state){ console.log(JSON.parse(localStorage.getItem("listd")) === null); if(JSON.parse(localStorage.getItem("listd")) === null){ let listd = state.list.filter((item) => { return item.checkbox; }); localStorage.setItem('listd',JSON.stringify(state.list)) state.list = listd localStorage.setItem('lists',JSON.stringify(state.list)) }else{ let lists = JSON.parse(localStorage.getItem("listd")) let listd = lists.filter((item) => { return item.checkbox; }); state.list = listd localStorage.setItem('lists',JSON.stringify(state.list)) } for (let i in state.tabs) { state.tabs[i].color = "black" } state.tabs[2].color = "red" localStorage.setItem('tab',JSON.stringify(state.tabs)) }, // 双击修改 dbTest(state,data){ state.list[data].readonly = false localStorage.removeItem('listd') localStorage.setItem('lists',JSON.stringify(state.list)) }, // 回车取消修改 readonly(state,data){ state.list[data].readonly = true localStorage.setItem('lists',JSON.stringify(state.list)) } }, actions: { }, modules: { } })
以上就是 vue 中实现 todos 具体效果的代码思路,不懂得也可以在评论区里问我,以后会持续发布一些新的功能,敬请关注。