vue项目开发-3

项目实战

筛选

  • 有三种筛选:
    • 全部:显示全部 todo
    • 进行中:显示未完成的 todo
    • 已完成:显示已完成的 todo
  • 用户是想要进行中的 todo 还是已完成的todo?
    • 可以发现用户会点击相应的按钮来表明他的意图
    • 如果在用户点击按钮时把他的意图传递给 Vue 对象
  • 给 data 增加一个属性 intention,来记录用户的意图
  • 定义三种意图:
    • all:想查看全部 todo
    • ongoing:想查看未完成的 todo
    • completed:想查看已完成的 todo
  • 需要根据用户的意图从 todos 中筛选 todo
    • 从 Vue 已绑定的数据中计算新的结果是计算属性的典型应用场景,所以加一个 filteredTodos 计算属性
    • 会发现未完成的 todo 分别在 filteredTodos 和 leftTodosCount 两个计算属性中被计算了两次
    • n 根据用户意图返回的结果:filteredTodos
  • 用户点击按钮的意图需要传给 Vue 对象
    • 设置让用户的意图在点击按钮时传给 Vue
    • 给各个筛选按钮绑定一个 click 事件
      • 之前在循环显示 todo 列表时使用的是 this.todos 的数据
      • 把循环的内容改为 filteredTodos
  • 循环过滤结果
<ul>
    <li v-for='todo in filteredTodos' :key='todo.id'>
  • 绑定事件
<span>筛选:
    <input type="button" class="selected" value="全部"
           @click="intention='all'">
    <input type="button" value="进行中" 
           @click="intention='ongoing'">
    <input type="button" value="已完成"
           @click="intention='completed'">
  • vue对象增加data属性和计算属性
			data: function () {
     
...
					intention: 'all' 
...
			computed: {
     
...
					leftTodos(){
     
						return this.todos.filter(todo => !todo.completed)
					},
					leftTodoCount(){
     
						return this.leftTodos.length
					},
					filteredTodos(){
     
						if(this.intention == 'ongoing'){
     
							return this.leftTodos
						}else if (this.intention == 'completed'){
     
							return this.todos.filter(todo => todo.completed)
						}else {
      //返回所有的
							return this.todos
						}
					}

功能10:样式绑定

  • 使用v-bind:class绑定
<span>筛选:
    <input type="button" class="selected" value="全部"
           @click="intention='all'"
           v-bind:class="{selected: intention==='all'}">
    <input type="button" value="进行中" 
           @click="intention='ongoing'"
           v-bind:class="{selected: intention==='ongoing'}">
    <input type="button" value="已完成"
           @click="intention='completed'"
           v-bind:class="{selected: intention==='completed'}">

批量清除

  • 只要把筛选出来的 todo 从 todos 列表删除就可以了
    • 先为按钮绑定事件
    • 然后实现相应的绑定方法
  • 绑定事件
<input type="button" value="清除已完成"
       @click="clearCompleted">
<input type="button" value="清除全部"
       @click="clearAll">
  • 实现方法methods
clearCompleted(){
     
    this.todos = this.todos.filter(todo => !todo.completed)
},
clearAll(){
     
    this.todos = []
}

功能11:动态显示按钮

  • 绑定v-if条件刷选
			  <span>筛选:
...
			    <input v-if="leftTodoCount" type="button" value="进行中" 
						@click="intention='ongoing'"
						v-bind:class="{selected: intention==='ongoing'}">
			    <input v-if="completedTodoCount" type="button" value="已完成"
						@click="intention='completed'"
						v-bind:class="{selected: intention==='completed'}">
			    <input v-if="completedTodoCount" type="button" value="清除已完成"
						@click="clearCompleted">
  • 增加和修改计算属性
computed: {
     
    ...
    completedTodos(){
     
        return this.todos.filter(todo => todo.completed)
    },
        completedTodoCount(){
     
            return this.completedTodos.length
        },

功能12:用户体验

  • 增加span的v-if
<div>
    <span v-if="leftTodoCount">剩余 {
    { leftTodoCount }} 项未完成 ---span>
    <span v-else-if="completedTodoCount">全部完成,你真是太优秀了span>
    <span v-else>添加我的第一个TODOspan>

  • 增加清除确认
clearCompleted(){
     
    if(!confirm('确定清除已完成的待办事项?')){
     
        return
    }
    this.todos = this.todos.filter(todo => !todo.completed)
},
    clearAll(){
     
        if(!confirm('确定清除全部的待办事项?')){
     
            return
        }
        this.todos = []
    }

功能13:回收站

  • 添加一个回收站data对象:recycleBin
			data: function () {
     
				return {
     
...
					recycleBin:[], //回收站

  • 添加删除标记:removed
			            addTodo: function () {
     
...
			                this.todos.push({
     id: id++, title: this.newTodoTitle,
											completed:false, removed:false});
...
			            },

  • 修改removedTodo,clearCompleted,clearAll,将删除数据移动到回收站
removeTodo(todo){
     
    let pos = this.todos.indexOf(todo);
    let removedTodo = this.todos.splice(pos, 1)[0];
    removedTodo.removed = true;
    this.recycleBin.unshift(removedTodo)
},
    clearCompleted(){
     
        if(!confirm('确定清除已完成的待办事项?')){
     
            return
        }
        this.completedTodos.map(todo => todo.removed = true)
        this.recycleBin.unshift(...this.completedTodos)
        this.todos = this.leftTodos
    },
        clearAll(){
     
            if(!confirm('确定清除全部的待办事项?')){
     
                return
            }
            this.todos.map(todo => todo.removed = true)
            this.recycleBin.unshift(...this.todos)
            this.todos = []
        }

  • DOM增加回收站按钮,绑定事件
<input v-if="recycleBin.length" type="button" value="回收站"
       @click="intention='removed'">
...

					filteredTodos(){
     
...
						}else if (this.intention == 'removed'){
     
							return this.recycleBin
...
					}

从回收站还原

  • 还原按钮
		        <li v-for='todo in filteredTodos' :key='todo.id'>
...
				  <input v-if="todo.removed" type="button" value="还原" 
						@click="restoreTodo(todo)"/>
				  <input v-else="todo.removed" type="button" value="删除" 
						@click="removeTodo(todo)"/>

  • 添加方法
restoreTodo: function(todo){
     
    todo.removed = false
    this.todos.unshift(todo) //恢复
    pos = this.recycleBin.indexOf(todo)
    this.recycleBin.splice(pos, 1)
},

本地存储

  • Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性
    vue项目开发-3_第1张图片

  • 现在只要一刷新浏览器,所有todo 都没了,因为的数据保存在内存中,页面刷新数据就会清除

  • 可以使用浏览器的 LocalStorage 来实现数据的持续性存储

    • 这样一来只要用户不删除浏览器缓存,todo 会一直在
    • 当然浏览器清除缓存后数据也没有了
    • 为了更加持久化存储,可以使用数据库,这里只是用 LocalStorage
  • 首先来定义一个对象,用于 LocalStorage 存储和获取 todo 的相关操作

    • STORAGE_KEY 用来区分存储到 LocalStorage 的内容,因为 LocalStorage 中可能存储其它应用的数据,使用这个 key 用于区分
    • todoStorage 是一个 JavaScript 的对象,它的属性是两个方法
      • save 方法:把 todos 转为 JSON 格式,然后将序列化的数据存入对应 key 为 STORAGE_KEY 的本地存储中
      • fetch 方法:从对应 STORAGE_KEY 的本地存储将之前存入的 todo 数据取出并反序列化
  • 为 todoStorage 对象绑定一个 uid 属性,作用是后续添加 todo 时,用于确定新添加todo 的 id

    • 注意这里代码中的 localStorage 就代表了本地存储对象,在支持 HTLM5 的浏览器中会存在这个对象,直接引用即可
  • 每当用户打开页面时,因为去 LocalStorage fetch 一下存储的数据

  • 当添加 todo 时,由于可能已经存在从本地取出的 todo 数据,新的 todo id 不能是从 0 开始了,而应该从已有 todoStorage.uid 开始

    • 一旦添加了新的 todo,应该及时将新的 todo 存到本地,防止用户不小心关闭页面而导致数据丢失
    • 可以使用 Vue 的 watch 来监听用户添加 todo 的事件,即监视 this.todos 的变化,一旦改变,立即修改本地存储的 todos 的数据
  • 定义localstorage存储和获取todo

	<script>
		let id = 0; // 用于 id 生成
		var STORAGE_KEY = "dylan-vue2-todo"
		var todoStorage = {
     
			fetch(){
      //读
				var todos = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]')
				todos.forEach(function(todo, index){
     
					todo.id = index
				});
				todoStorage.uid = todos.length
				return todos
			},
			save(todos){
      //写
				localStorage.setItem(STORAGE_KEY,JSON.stringify(todos))
			}
		};

  • 修改data
			data: function () {
     
				return {
     
					todos: todoStorage.fetch(),
                    ...

  • 修改addTodo
			            addTodo: function () {
     
...
			                this.todos.push({
     id: todoStorage.uid++, title: this.newTodoTitle,
...

  • 增加监听
watch:{
     
    todos:{
     
        handler: function(todos){
     
            todoStorage.save(todos)
        },
            deep: true
    }
},

你可能感兴趣的:(web前端开发,vue.js)