vue项目todolist

初始化项目

(1)先把vue项目创建出来

(2)然后把src中的文件替换掉,替换成我们项目的文件

(3)创建3个组件,头部组件(TodoHeader),身体组件(TodoMain),结尾组件(TodoFooter)

(4)把样式导入App.vue中去

(5)把数据列表传入进去

TodoMain获取父组件数据,进行传值

父组件使用自定义属性,动态把list数组传递给子组件

子组件使用props进行接收,然后使用v-for对页面进行渲染

App.vue使用自定义属性,传递参数

<TodoMain :list="list"></TodoMain>  //父传子

TodoMain使用props进行接收,然后使用v-for对页面进行渲染

//子组件对父组件进行接收 
 props : {
    list : {
      type : Array,
      required : true
    }
  }
//子组件使用v-for对页面进行渲染
      <!-- 当任务已完成,可以给 li 加上 completed 类,会让元素加上删除线 -->
      <li :class="{completed : item.isDone}" v-for="(item,index) in list" :key="item.id" >
        <div class="view">
          <input class="toggle" type="checkbox" v-model="item.isDone"/>
          <label>{{ item.name }}</label>
          <button class="destroy"></button>
        </div>
      </li>

删除功能

子组件不能直接对父组件传过来的数据进行修改,所以子组件需要把方法传递给父组件,父组件完成删除操作

 TodoMain组件创建事件,并且暴漏给父组件

<button class="destroy" @click="del(item.id)"></button>
//子组件创建事件,暴漏给父组件
  methods : {
    del (id) {
      // console.log(id)
      this.$emit(`del`,id)
    }
  }

父组件进行接收,并且为子组件提供一个方法

    <TodoMain :list="list" @del="fuDel"></TodoMain> //父组件接收子组件的传值
//父组件为子组件创建一个方法
  methods : {
    fuDel (id) {
     this.list = this.list.filter(i => { return i.id !== id })
    }
  }

 点击选中按钮,进行删除线绑定

因为我们使用的是v-model进行删除线绑定的,违反了,子组件不能修改父组件原则,所以我们使用v-bind进行数据绑定

然后使用v-on:change事件对按钮进行监听,然后使用父组件传递数据给子组件

TodoMain子组件重新进行绑定,并且传值给父组件

          <input class="toggle" type="checkbox" :checked="item.isDone" @change="change(item.id)"/>

    change(id) {
      // console.log(id)
      this.$emit(`change`,id) //子组件进行传值
    }

App.vue父组件进行接收,并且对isDome状态进行修改

    <TodoMain :list="list" @del="fuDel" @change="fuChange"></TodoMain>

fuChange (id) {
      // console.log(id) //拿到状态以后遍历数组,当我们点击的时候对属性进行切换
      this.list.forEach(i => { //这里我们已经动态绑定checked属性,当item.isDone为true的时候,添加删除线
        if (i.id === id) {  //判断是否是我们点击的id值
          i.isDone = !i.isDone //我们让i.isDome取反,然后传递给动态的checked事件
        }
      })
    }

TodoHeader输入进行添加

我们先获取到输入框中的数值,然后子组件传递给父组件,父组件进行添加

TodoHeader我们首先绑定一个v-model获取表单框中输入的信息,然后创建回车添加事件,暴漏给父级

    <input class="new-todo" placeholder="请输入任务名称" autofocus v-model.trim="name" @keyup.enter="tian" />

  data () {
    return {
      name : ``  //在data中声明一个name属性,获取表单中的数值
    }
  },
  methods : {
    tian () {
      // console.log(this.name) //获取到添加的数据
      this.$emit(`tian`,this.name)
      this.name = `` //把name更换成为控制,每次回车以后,确保输入框内容被清空掉了
    }
  }

App.vue使用自定义属性进行接收,然后在methods添加子组件传递过来数据

    <TodoHeader @tian="fuTian"></TodoHeader>

    fuTian (name) {
      // console.log(name)
      this.list.push({
        id: Date.now(),
        name : name, //这里前边一个是list中的name属性,后边的是传入的name的属性
        isDone: false
      })
    }

TodoFooter,尾部组件进行修改

TodoFooter,获取父组件的传值,对剩余项目的判断

TodoFooter首先接收父亲的传值

TodoFooter接收父亲的传值

  props : {
    list : {
      type : Array,
      required : true
    }
  },

App.vue进行对子组件的传值

    <TodoFooter :list="list"></TodoFooter>

TodoFooter然后使用computed监视已经完成的数组的长度,然后动态渲染未完成的到页面

最后判断数组的长度是否为,如果数组长度为0的情况下隐藏底部

  <footer class="footer" v-if="show"> //如果数组长度为0,页面底部属性隐藏
    <span class="todo-count"><strong>{{ length > 0 ?`剩余 ${length}` : `全部完成`}}</strong></span>

  computed : { //创建监视属性,因为我们不需要对页面进行修改,可以节省创建
    length () {
     return this.list.filter(i => i.isDone === false).length //求出未完成数组的长度
    },
    show () {
      // console.log()
      return this.list.length > 0 ? true : false
    }
  }

TodoFooter显示隐藏清除全部,清空按钮清空功能

TodoFooter如果我们没有已完成的,不显示清除全部按钮,如果我们有已完成的隐藏显示按钮

    <button class="clear-completed" v-if="qing">清除已完成</button>
qing () {
      //当我们任何一项的is.Done===true的时候我们就显示按钮,反之如果我们所有项false的时候就隐藏按钮
      return this.list.some(i => i.isDone === true)
    }

TodoFooter清除我们已经完成的项,添加点击事件,然后暴漏给父组件,父组件获取以后进行数组修改

    <button class="clear-completed" v-if="qing" @click="Del">清除已完成</button>

  methods : {
    Del () {
      // console.log(`清除`)
      this.$emit(`Del`)
    }
  }

App.vue父组件进行接收子组件传值,并且进行修改

    <TodoFooter :list="list" @Del="FuDel"></TodoFooter>

    FuDel () {
     this.list = this.list.filter(i => {
        return i.isDone !== true
      })
    }

TodoFooter底部高亮效果

首先添加点击事件,然后添加动态属性,最后添加type属性,进行对比,如果为true显示,为false的时候进行隐藏

首先我们的红色外边框属性是selected,我们使用动态绑定,绑定class属性,当class属性为true的时候,我们让他显示出来

动态决定是否为true

我们在data中创建一个type属性,给type属性设置一个all的默认值,然后判断,动态class属性判断为true的时候显示出来红色边框

最后我们添加一个点击事件,每次点击的时候都会给data传递一个参数,进行判断,让calss属性为true或者false

所以每次我们点击的时候,会把参数传递给data的type属性,然后使用type属性和我们的定义的值进行对比,当对比为true的时候边框显示,false的时候边框不显示

    <ul class="filters">
      <li>
        <a :class="{selected : type === `all`}" href="#/" @click="color(`all`)">全部</a>
      </li>
      <li>
        <a :class="{selected : type === `active`}" href="#/active"  @click="color(`active`)">进行中</a>
      </li>
      <li>
        <a :class="{selected : type ===`completed`}" href="#/completed"  @click="color(`completed`)">已完成</a>
      </li>
    </ul>

  data () {
    return {
      type : `all` //创建type属性
    }
  },
  methods : {
    Del () {
      // console.log(`清除`)
      this.$emit(`Del`)
    },
    color (type) { //点击事件,获取点击的参数,然后使用参数给data数据进行赋值
      this.type = type
    }
  }

TodoFooter状态提升,让父组件管理点击事件,然后可以让别的组件也获取到点击信息

将type状态提升到父组件中

首先App.vue父组件创建type属性传值给子组件,然后子组件进行接收

    <TodoFooter :list="list" @Del="FuDel" @Color="color" :type="type"></TodoFooter>
  data () {
    return {
      list: [
        { id: 1, name: '读万卷书', isDone: true },
        { id: 2, name: '行万里路', isDone: false },
        { id: 3, name: '学而时习之', isDone: true },
      ],
      type : `all`
    }
  },

TodoFooter子组件进行接收(记得注销掉data中的type属性,因为以后就使用父组件中的type属性)

  props : {
    list : {
      type : Array,
      required : true
    },
    type : {
      type : String
    }
  },

TodoFooter子组件进行传值给父组件实现点击事件

color (type) { //点击事件,获取点击的参数,然后使用参数给data数据进行赋值
      // this.type = type
      this.$emit(`Color`,type)
    }

App.vue父组件进行处理,然后返回给子组件

    <TodoFooter :list="list" @Del="FuDel" @Color="color" :type="type"></TodoFooter>

    color (type) {
      this.type = type
    }

TodoMain完成下边点击以后的过滤功能

在TodoMain中判断isDome是否为true或者false,然后显示出来,使用新值进行遍历渲染页面

我们首先获取到App.vue父组件的type值,父组件先给子组件进行传值

    <TodoMain :list="list" @del="fuDel" @change="fuChange" :type="type"></TodoMain>

然后子组件进行接收,并且进行判断,渲染的数据

  props : {
    list : {
      type : Array,
      required : true
    },
    type : { //接收父组件的传值
      type : String
    }
  },

判断父组件传递过来的数值,我们重新赋值,然后对页面进行判读渲染

  computed : {
    xinList () {
      if (this.type === `completed`) { //显示已经完成的
        return this.list.filter(i => i.isDone === true)
      } else if (this.type === `active`) { //显示未完成的
        return this.list.filter(i => i.isDone === false)
      } else { //剩余的就是全部数组
        return this.list
      }
    }
  }

最后我们把新的数组数据渲染到页面上边

      <li :class="{completed : item.isDone}" v-for="(item,index) in xinList" :key="item.id" >

 

本地储存功能

我们把数据先储存到本地,然后父组件重新获取本地的数据,对子组件进行传值

我们在App.vue父组件中进行动态监视,监视每次数据的变化进行储存

watch : {
list : {
handler (value) {
// 可以判断数据是否更改,当数据进行更改的时候,进行储存
// 先转换数据类型为字符串类型,然后储存到名字叫做todo的本地缓存的值中
localStorage.setItem(`todo`,JSON.stringify(value))
},
deep : true //开启深度监听,可以监听数组
}
}

我们每次获取数据的时候,直接在网页中进行获取

  data () {
    return {
      // list: [
      //   { id: 1, name: '读万卷书', isDone: true },
      //   { id: 2, name: '行万里路', isDone: false },
      //   { id: 3, name: '学而时习之', isDone: true },
      // ],
      // 每次获取list数据的时候,都是从本地获取,如果说没有数据,就返回一个空的数组
      list : JSON.parse(localStorage.getItem(`todo`)) || [],
      type : `all`
    }
  },

TodoHeader全部选中功能,(双向数据绑定)

栓修改那个数据绑定,然后添加监视事件

    <input id="toggle-all" class="toggle-all" type="checkbox" v-model="quan" />
computed : {
xinList () {
if (this.type === `completed`) { //显示已经完成的
return this.list.filter(i => i.isDone === true)
} else if (this.type === `active`) { //显示未完成的
return this.list.filter(i => i.isDone === false)
} else { //剩余的就是全部数组
return this.list
}
},
quan () {
return this.list.every(i => i.isDone === true)
}

 然后传递给父组件让父组件进行双向数据绑定和修改

    <input id="toggle-all" class="toggle-all" type="checkbox" v-model="quan" />
    
quan : {
      get () {
        return this.list.every(i => i.isDone === true)
      },
      set (value) {
        this.$emit(`quan`,value)
      }
    }
    <TodoMain :list="list" @del="fuDel" @change="fuChange" :type="type" @quan="quan"></TodoMain>
    quan (value) {
      this.list.forEach((item) => (item.isDone = value))
    }

 

posted @ 2023-01-05 18:32  帅气丶汪星人  阅读(190)  评论(0)    收藏  举报