整体效果
vue3-todolist.png
父子组件传值
父组件
父子传值-父组件.png
子组件
父子传值-子组件.png
父子传值--子组件.png
mutations 处理操作
mutations 处理操作.png
Home.vue 接收来自 store 中的数据
接收store的数据.png
代码展示
状态管理index.js
import { createStore } from 'vuex'
export default createStore({
  state: {
    list:[
      {
          title:'吃饭',
          complete:false
      },
      {
          title:'睡觉',
          complete:true
      },
      {
          title:'敲代码',
          complete:false
      },
  ]
  },
  mutations: {
    addTodo(state, payload){
      state.list.push(payload)
    },
    delTodo(state,payload){
      state.list.splice(payload,1)  // 删除任务 splice(下标,个数)
    },
    clear(state,payload){
      state.list = payload
    }
  },
  actions: {
  },
  modules: {
  }
})
组件App.vue
该组件作为入口组件
<template>
  <div>
      <router-view/>
  </div>
</template>
<style lang="scss" scoped>
*{
  margin: 0;
  padding: 0;
}
div{
  width: 800px;
  margin: 50px auto;
}
</style>
组件Home.vue
<template>
  <div>
    <nav-header @add="add"></nav-header>
    <nav-main :list="list" @del="del"></nav-main>
    <nav-footer :list="list" @clear="clear"></nav-footer>
  </div>
</template>
<script>
  import NavHeader from '@/components/navHeader/NavHeader';
  import NavMain from '@/components/navMain/NavMain';
  import NavFooter from '@/components/navFooter/NavFooter';
  import { computed, ref } from 'vue';
  import { useStore } from 'vuex';
 export default {
    components:{
      NavHeader,
      NavMain,
      NavFooter
    },
    setup() {
      let store = useStore()
      let list = computed(()=>{
        return store.state.list
      })
      let value = ref('')
      let add = (val) =>{
        value.value = val
        let flag = true
        list.value.map(item=>{
          if(item.title == value.value){
            flag =false
            alert('任务已存在')
          }
        })
        if(flag){
          store.commit('addTodo',{   // 调用mutations
          title:value.value,
          complete:false
        })
        }
      }
      let del = (val) => {
        store.commit('delTodo',val)
      }
      let clear = (val) => {
        store.commit('clear',val)
      }
      return {
        add,
        value,
        list,
        del,
        clear
      }
    }
 }
</script>
组件NavHeader.vue
<template>
    <div>
        <input type="text"
         placeholder="请输入任务名称" @keydown.enter = "enter" v-model="value">
    </div>
</template>
<script>
import { defineComponent,ref } from 'vue'
export default defineComponent({
    setup(props, ctx) {
        let value = ref('')
        let enter = () => {
            ctx.emit('add',value.value)
            console.log(value.value);
            value.value = ''
        }
        return{
            value,
            enter
        }
    }
});
</script>
<style lang="scss" scoped>
    input{
        margin-bottom: 10px;
    }
</style>
组件NavMain.vue
<template>
    <div>
        <div v-if="list.length>0">
            <div v-for="(item,index) in list" :key="index">
                <div class="item">
                    <input type="checkbox" name="" id="" v-model="item.complete">
                    {{item.title}}
                    <button class="del" @click="del(item, index)">删除</button>
                </div>
            </div>
        </div>
        <div v-else>
            暂无任务
        </div>
    </div>
</template>
<script>
    import { defineComponent, ref } from 'vue'
   export default defineComponent({
       props:{
           list:{
               type:Array,
               required:true
           }
       },
       emits:['del'], // 放分发事件的属性名字  没有这句浏览器控制台有报错
       setup(props,ctx){
            
            let del = (item,index)=>{
                ctx.emit('del',index)
            }
            return{
                del
            }
       }
   })
</script>
<style lang="scss">
    .item{
        height: 35px;
        line-height: 35px;
        position: relative;
        width: 160px;
        cursor: pointer;
        button{
            position: absolute;
            right: 20px;
            top: 6px;
            display: none;
            z-index: 99;
        }
        &:hover{
            background-color: #ddd;
            button{
                display: block;
            }
        }
    }
</style>
组件NavFooter.vue
<template>
    <div class="container">
        <div>
            已完成{{isComplete}} / 全部{{list.length}}
        </div>
        <div v-if="isComplete > 0" class="btn">
            <button @click="clear">清除已完成</button>
        </div>
    </div>
</template>
<script>
    import { defineComponent, ref, computed } from 'vue'
   export default defineComponent({
    props:{
           list:{
               type:Array,
               required:true
           }
       },
       setup(props,ctx){
           let isComplete = computed(()=>{
               let arr = props.list.filter(item => {
                   return item.complete    // 过滤已完成
               })
               return arr.length
           })
            let clear = () =>{
                let arr = props.list.filter(item => {
                   return item.complete === false   // 过滤未完成的
               })
                ctx.emit('clear',arr)
            }
           return {
               isComplete,
               clear
           }
       }
   })
</script>
<style lang="scss" scoped>
    .container{
        display: flex;
        align-items: center;
        .btn{
            margin-left: 10px;
        }
    }
</style>











网友评论