美文网首页
用 vue3 写的简洁的 todolist 案例

用 vue3 写的简洁的 todolist 案例

作者: 小小前端搬运工 | 来源:发表于2022-03-15 01:53 被阅读0次

    整体效果

    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>
    

    相关文章

      网友评论

          本文标题:用 vue3 写的简洁的 todolist 案例

          本文链接:https://www.haomeiwen.com/subject/ksyedrtx.html