• vue part3.2 小案例 todo 列表展示删除


    TODO....

    原始html

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1.0">
        <!--<link rel="stylesheet" href="./static/css/bootstrap.css">-->
        <title>vue_demo</title>
    
        <style>
        .todo-container {
         600px;
        margin: 0 auto;
        }
        .todo-container .todo-wrap {
          padding: 10px;
          border: 1px solid #ddd;
          border-radius: 5px;
        }
    
    
          .todo-main {
        margin-left: 0px;
        border: 1px solid #ddd;
        border-radius: 2px;
        padding: 0px;
      }
      .todo-empty {
        height: 40px;
        line-height: 40px;
        border: 1px solid #ddd;
        border-radius: 2px;
        padding-left: 5px;
        margin-top: 10px;
      }
    
         /*item*/
      li {
        list-style: none;
        height: 36px;
        line-height: 36px;
        padding: 0 5px;
        border-bottom: 1px solid #ddd;
      }
      li label {
        float: left;
        cursor: pointer;
      }
      li label li input {
        vertical-align: middle;
        margin-right: 6px;
        position: relative;
        top: -1px;
      }
      li button {
        float: right;
        display: none;
        margin-top: 3px;
      }
      li:before {
        content: initial;
      }
      li:last-child {
        border-bottom: none;
      }
    
          /*footer*/
         .todo-footer {
        height: 40px;
        line-height: 40px;
        padding-left: 6px;
        margin-top: 5px;
      }
      .todo-footer label {
        display: inline-block;
        margin-right: 20px;
        cursor: pointer;
      }
      .todo-footer label input {
        position: relative;
        top: -1px;
        vertical-align: middle;
        margin-right: 5px;
      }
      .todo-footer button {
        float: right;
        margin-top: 5px;
      }
    
        </style>
    
      </head>
    
      <body>
        <div id="app">
      <div class="todo-container">
        <div  class="todo-wrap">
          <div class="todo-header">
            <input type="text" placeholder="请输入你的任务名称,按回车键确认" >
          </div>
    
          <ul class="todo-main">
            <li :style="{background: bgColor}">
              <label>
                <input type="checkbox">
                <span>todotitle</span>
              </label>
              <button class="btn btn-danger" >删除</button>
            </li>
          </ul>
    
          <div class="todo-footer">
            <label>
              <input type="checkbox" >
            </label>
            <span>
              <span>已完成</span>/全部
            </span>
            <button class="btn btn-danger" >清除已完成任务</button>
          </div>
        </div>
      </div>
    
    
        </div> <!--app -->
      </body>
    
    </html>
    View Code

    补充

    当内部有嵌套div时  (回字结构)

    onmouseenter  onmouseleave  仅对外层边界有触发

    onmouseover  onmounseout   对内部边界也有触发

    reduce  forEach  filter

    1. step1 基本功能

    index.html

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1.0">
        <!--<link rel="stylesheet" href="./static/css/bootstrap.css">-->
        <title>vue_demo</title>
    
        <style>
        .todo-container {
         600px;
        margin: 0 auto;
        }
        .todo-container .todo-wrap {
          padding: 10px;
          border: 1px solid #ddd;
          border-radius: 5px;
        }
    
    
          .todo-main {
        margin-left: 0px;
        border: 1px solid #ddd;
        border-radius: 2px;
        padding: 0px;
      }
      .todo-empty {
        height: 40px;
        line-height: 40px;
        border: 1px solid #ddd;
        border-radius: 2px;
        padding-left: 5px;
        margin-top: 10px;
      }
    
         /*item*/
      li {
        list-style: none;
        height: 36px;
        line-height: 36px;
        padding: 0 5px;
        border-bottom: 1px solid #ddd;
      }
      li label {
        float: left;
        cursor: pointer;
      }
      li label li input {
        vertical-align: middle;
        margin-right: 6px;
        position: relative;
        top: -1px;
      }
      li button {
        float: right;
        display: none;
        margin-top: 3px;
      }
      li:before {
        content: initial;
      }
      li:last-child {
        border-bottom: none;
      }
    
          /*footer*/
         .todo-footer {
        height: 40px;
        line-height: 40px;
        padding-left: 6px;
        margin-top: 5px;
      }
      .todo-footer label {
        display: inline-block;
        margin-right: 20px;
        cursor: pointer;
      }
      .todo-footer label input {
        position: relative;
        top: -1px;
        vertical-align: middle;
        margin-right: 5px;
      }
      .todo-footer button {
        float: right;
        margin-top: 5px;
      }
    
        </style>
    
      </head>
    
      <body>
        <div id="app">
    
    
    
        </div> <!--app -->
      </body>
    
    </html>
    View Code

    main.js

    /**
     * Created by infaa on 2018/9/19.
     */
    import Vue from 'vue'
    import App from './App'
    
    import './base.css'
    /* eslint-disable no-new */
    
    new Vue({
      el: '#app',
      components: {App},
      template: '<App/>'
    })
    View Code

    base.css

    body {
      background: #fff;
    }
    
    .btn {
      display: inline-block;
      padding: 4px 12px;
      margin-bottom: 0;
      font-size: 14px;
      line-height: 20px;
      text-align: center;
      vertical-align: middle;
      cursor: pointer;
      box-shadow: inset 0 1px 0 rgba(225, 225, 225, 0.2), 0 1px 2px rgba(0, 0, 0,0.15);
      border-radius: 4px;
    }
    
    .btn-danger {
      color: #fff;
      background-color: #da4f49;
      border: 1px solid #bd362f;
    }
    
    .btn-danger:hover {
      color: #fff;
      background-color: #bd362f;
    }
    
    .btn:focus {
      outline: none;
    }
    View Code

    app.vue

    <template>
    <div class="todo-container">
        <div  class="todo-wrap">
          <TodoHeader :addTodo="addTodo"></TodoHeader>
          <TodoList :todos="todos" :deleteTodo="deleteTodo"></TodoList>
          <TodoFooter :todos="todos" :deleteCompleteTodos="deleteCompleteTodos" :selectAllTodos="selectAllTodos"></TodoFooter>
        </div>
      </div>
    </template>
    
    <script>
    import TodoHeader from './components/TodoHeader.vue'
    import TodoList from './components/TodoList.vue'
    import TodoFooter from './components/TodoFooter.vue'
    export default {
      components: {
        TodoHeader,
        TodoList,
        TodoFooter
      },
      data () {
        return {
          todos: [
            {title: '吃饭', complete: false},
            {title: '睡觉', complete: true},
            {title: 'coding', complte: false}
          ]
        }
      },
      methods: {
        addTodo (todo) {
          this.todos.unshift(todo)
        },
        deleteTodo (index) {
          this.todos.splice(index, 1)
        },
        deleteCompleteTodos () {
          this.todos = this.todos.filter(todo => !todo.complete)
        },
        selectAllTodos (check) {
          this.todos.forEach(todo => (todo.complete = check))
        }
      }
    }
    
    </script>
    
    <style>
    
    </style>
    View Code

    components/TodoHeader.vue

    <template>
          <div class="todo-header">
            <input type="text" placeholder="请输入你的任务名称,按回车键确认" v-model="title" @keyup.enter="addItem">
          </div>
    </template>
    
    <script>
    export default {
      props: {
        addTodo: Function
      },
      data () {
        return {
          title: ''
        }
      },
      methods: {
        addItem () {
          const title = this.title.trim()
          const addTodo = this.addTodo
          if (!title) {
            alert('title Kong')
            return
          }
          const todo = {
            title,
            complete: false
          }
          addTodo(todo)
          this.title = '' // 注意这里要操作this对象而不是函数内局部变量title
          // 验证合法性  生成对象  添加  还原
        }
      }
    }
    
    </script>
    
    <style>
    
    </style>
    View Code

    components/TodoList.vue

    <template>
          <ul class="todo-main">
            <TodoItem v-for="(todo,index) in todos" :todo="todo" :key="index" :index="index" :deleteTodo="deleteTodo"></TodoItem>
          </ul>
    </template>
    
    <script>
    import TodoItem from './TodoItem.vue'
    export default {
      props: {
        todos: Array,
        deleteTodo: Function
      },
      components: {
        TodoItem
      }
    
    }
    
    </script>
    
    <style>
    
    </style>
    View Code

    components/TodoItem.vue

    <template>
            <li :style="{background: bgColor}" @mouseenter="handleEnter(true)" @mouseleave="handleEnter(false)">
              <label>
                <input type="checkbox" v-model="todo.complete">
                <span>{{todo.title}}</span>
              </label>
              <button class="btn btn-danger" @click="deleteItem" v-show="isShow">删除</button>
            </li>
    </template>
    
    <script>
    export default {
      props: {
        todo: Object,
        index: Number,
        deleteTodo: Function
      },
      data () {
        return {
          isShow: false,
          bgColor: 'white'
        }
      },
      methods: {
        deleteItem () {
          const index = this.index
          const todo = this.todo
          const deleteTodo = this.deleteTodo
          if (window.confirm(`删除${todo.title}`)) {
            deleteTodo(index)
          }
        },
        handleEnter (isEnter) {
          if (isEnter) {
            this.isShow = true
            this.bgColor = 'grey'
          } else {
            this.isShow = false
            this.bgColor = 'white'
          }
        }
      }
    }
    
    </script>
    
    <style>
    
    </style>
    View Code

    components/TodoFooter.vue

    <template>
          <div class="todo-footer">
            <label>
              <input type="checkbox" v-model="isAllChecked">
            </label>
            <span>
              <span>已完成{{completeSize}}</span>/全部{{todos.length}}
            </span>
            <button class="btn btn-danger" v-show="completeSize" @click="deleteCompleteTodos">清除已完成任务</button>
          </div>
    </template>
    
    <script>
    export default {
      props: {
        todos: Array,
        deleteCompleteTodos: Function,
        selectAllTodos: Function
      },
      computed: {
        completeSize () {
          const todos = this.todos
          return todos.reduce((preTotal, todo) => preTotal + (todo.complete ? 1 : 0), 0)
        },
        isAllChecked: {
          get () {
            return this.completeSize === this.todos.length && this.todos.length > 0
          },
          set (value) {
            this.selectAllTodos(value)
          }
        }
      }
    }
    
    </script>
    
    <style>
    
    </style>
    View Code

    2. 本地存储

    实现刷新后不消失,关闭浏览器重新打开依然有效。

    保存于浏览器localstorage

    app.vue

    <template>
    <div class="todo-container">
        <div  class="todo-wrap">
          <TodoHeader :addTodo="addTodo"></TodoHeader>
          <TodoList :todos="todos" :deleteTodo="deleteTodo"></TodoList>
          <TodoFooter :todos="todos" :deleteCompleteTodos="deleteCompleteTodos" :selectAllTodos="selectAllTodos"></TodoFooter>
        </div>
      </div>
    </template>
    
    <script>
    import TodoHeader from './components/TodoHeader.vue'
    import TodoList from './components/TodoList.vue'
    import TodoFooter from './components/TodoFooter.vue'
    export default {
      components: {
        TodoHeader,
        TodoList,
        TodoFooter
      },
      data () {
        return {
          todos: JSON.parse(window.localStorage.getItem('todos_key') || '[]')
        }
      },
      methods: {
        addTodo (todo) {
          this.todos.unshift(todo)
        },
        deleteTodo (index) {
          this.todos.splice(index, 1)
        },
        deleteCompleteTodos () {
          this.todos = this.todos.filter(todo => !todo.complete)
        },
        selectAllTodos (check) {
          this.todos.forEach(todo => (todo.complete = check))
        }
      },
      watch: {
        todos: {
          deep: true,
          handler: function (value) {
            window.localStorage.setItem('todos_key', JSON.stringify(value))
          }
        }
    
      }
    }
    
    </script>
    
    <style>
    
    </style>
    View Code

     由于todos是列表, 监听为deep,和python deepcopy  类似关注内部元素的内存地址。

    把存储抽取为util

    app.vue

    <template>
    <div class="todo-container">
        <div  class="todo-wrap">
          <TodoHeader :addTodo="addTodo"></TodoHeader>
          <TodoList :todos="todos" :deleteTodo="deleteTodo"></TodoList>
          <TodoFooter :todos="todos" :deleteCompleteTodos="deleteCompleteTodos" :selectAllTodos="selectAllTodos"></TodoFooter>
        </div>
      </div>
    </template>
    
    <script>
    import TodoHeader from './components/TodoHeader.vue'
    import TodoList from './components/TodoList.vue'
    import TodoFooter from './components/TodoFooter.vue'
    import storageUtil from './util/storageUtil.js'
    export default {
      components: {
        TodoHeader,
        TodoList,
        TodoFooter
      },
      data () {
        return {
          todos: storageUtil.readTodos()
        }
      },
      methods: {
        addTodo (todo) {
          this.todos.unshift(todo)
        },
        deleteTodo (index) {
          this.todos.splice(index, 1)
        },
        deleteCompleteTodos () {
          this.todos = this.todos.filter(todo => !todo.complete)
        },
        selectAllTodos (check) {
          this.todos.forEach(todo => (todo.complete = check))
        }
      },
      watch: {
        todos: {
          deep: true,
    //      handler: function (value) {
    ////        window.localStorage.setItem('todos_key', JSON.stringify(value))
    ////        storageUtil.saveTodos(value)
    //      }
          handler: storageUtil.saveTodos
        }
    
      }
    }
    
    </script>
    
    <style>
    
    </style>
    View Code

    storageUtil.js

    /**
     * Created by infaa on 2018/9/20.
     */
    const TODO_KEY = 'todos_key'
    export default {
      saveTodos(value) {
        window.localStorage.setItem(TODO_KEY, JSON.stringify(value))
      },
      readTodos() {
        return JSON.parse(window.localStorage.getItem(TODO_KEY) || '[]')
      }
    }
    View Code

    vue组件通信方式

    1. props

    2. vue自定义事件

    3. 消息订阅发布pusub库

    4.slot

    5 vuex

  • 相关阅读:
    C#中实现窗体间传值开发者在线 Builder.com.cn 更新时间:20080719作者: 来源:
    Visual C# 2005中如何产生与比较哈希值开发者在线 Builder.com.cn 更新时间:20080720作者: 来源:
    C#多线程编程实例实战开发者在线 Builder.com.cn 更新时间:20080720作者: 来源:
    如何构造一个C#语言的爬虫程序开发者在线 Builder.com.cn 更新时间:20080720作者: 来源:
    用C#读取Windows注册表中的多重字串和二进制字串开发者在线 Builder.com.cn 更新时间:20080720作者: 来源:
    Visual C#多线程参数传递浅析开发者在线 Builder.com.cn 更新时间:20080719作者: 来源:
    C#操作消息队列的代码开发者在线 Builder.com.cn 更新时间:20080720作者: 来源:
    深入解析C#编程中的事件开发者在线 Builder.com.cn 更新时间:20080719作者: 来源:
    理解C# 3.0新特性之Extension方法浅议开发者在线 Builder.com.cn 更新时间:20080719作者: 来源:
    什么东西打印出来好查,什么东西放在电脑好查
  • 原文地址:https://www.cnblogs.com/infaaf/p/9677312.html
Copyright © 2020-2023  润新知