• vue基础(五),对todos的操作


    对于totos的操作

    入口main.js文件

    // 引入vue
    
    import Vue from 'vue'
    // 引入App
    import App  from './App'
    
    // 配置vue对象
    
    new Vue({
      el:"#root",
      // 注册组件,渲染组件
      render : h=> h(App)
    
    })

    App组件

    <template>
      <div class="todo-container">
        <div class="todo-wrap">
          <Header :todos="todos" :updateO="updateO"></Header>
          <Main 
          :todos="todos" 
          :changeStatus= "changeStatus"
          :dltO="dltO"
          ></Main>
          <Footer :todos="todos"  :delQc="delQc"></Footer>
         
         
        </div>
      </div>
    </template>
    
    
    <script>
    
    // 引入组件
    import Header  from '@/components/Header'
    import Main  from  '@/components/Main'
    import Footer  from  '@/components/Footer'
    
    export default {
      name:'App',
      data() {
        return {
            todos:[
            {id:1,content:'抽烟', isOver:false},
            {id:2,content:'喝酒', isOver:true},
            {id:3,content:'烫头', isOver:false},
    
          ]
        };
      },
    
      methods:{
        //接收header的数据
        updateO(obj){
          //新增的对象的id是最后一个id加1
          let id =  this.todos[this.todos.length-1].id+1
          obj.id =id
          //数组往顶部新增一个对象
          this.todos.unshift(obj)
          console.log(this.todos)
        },
    
        //item组件点击单选框,改变状态
        changeStatus(index){
          //取反
          this.todos[index].isOver =  !this.todos[index].isOver
    
        },
    
        //item组件点击删除按钮
        dltO(index){
          this.todos.splice(index,1)
        },
    
        //对于footer组件中过滤的新数组赋值给原数组
        delQc(newTodos){
          this.todos =newTodos
    
        }
    
    
      },
    
    
      // 注册组件
      components:{
        Header,
        Main,
        Footer,
      }
    };
    
    </script>
    
    <style scoped  lang="less">
    /*app*/
    .todo-container {
      width: 600px;
      margin: 0 auto;
    }
    .todo-container .todo-wrap {
      padding: 10px;
      border: 1px solid #ddd;
      border-radius: 5px;
    }
    
    </style>

    Header组件

    <template>
      <div class="todo-header">
        <input type="text" placeholder="请输入你的任务名称,按回车键确认"  v-model="content"  @keyup.enter="update" />
      </div>
    </template>
    
    <script>
    export default {
      //输入框一个按键事件,添加li
    
      name:'Header',
      data() {
        return {
          content:'',
        };
      },
    
      // 接收父组件的数据
      props:{
        todos:Array,
        updateO:Function
      },
    
      methods:{
        //输入框输入数据,组成一个新对象,给父组件传递过去
        update(){
          let {content} =this
          if(content.trim()){
            //新对象
            let obj ={
              content,
              isOver:false
            }
    
            //传递数据给父组件
            this.updateO(obj)
            this.content=''
          }
        }
      }
    
    
    };
    </script>
    
    <style scoped  lang="less">
    /*header*/
    .todo-header input {
      width: 560px;
      height: 28px;
      font-size: 14px;
      border: 1px solid #ccc;
      border-radius: 4px;
      padding: 4px 7px;
    }
    
    .todo-header input:focus {
      outline: none;
      border-color: rgba(82, 168, 236, 0.8);
      box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
    }
    
    </style>

    Main组件

    <template>
      <ul class="todo-main">
        <Item 
          v-for="(todo, index) in todos" :key="todo.id"
          :todo="todo"
          :index="index"
          :changeStatus= "changeStatus"
          :dltO="dltO"
        ></Item>
       
      </ul>
    </template>
    
    <script>
    import Item from './Item'
    export default {
      name:'Main',
      data() {
        return {};
      },
    
      props:{
        todos:Array,
         changeStatus:Function,
         dltO:Function,
      },
    
      //注册组件
      components:{
        Item
      }
    };
    </script>
    
    <style scoped  lang="less">
    /*main*/
    .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;
    }
    </style>

    Item组件

    <template>
      <li  @mouseenter="isShow=true"  @mouseleave="isShow=false" :class="{myClass:isShow}">
        <label>
          <input type="checkbox" :checked="todo.isOver"  @click="changeZt" />
          <span>{{todo.content}}</span>
        </label>
        <button class="btn btn-danger" 
          v-show="isShow"
          @click="deleteO"
          
        
        >删除</button>
      </li>
    </template>
    
    <script>
    export default {
      //1.点击li中的单选按钮,需要父组件的数据更改状态,需要传递一个index参数,定位是那个li
      //2.点击删除按钮,需要父组件操作数组的逻辑,需要传递一个index参数,定位是那个li
      //3.移入,移出事件,li变化颜色,而且删除按钮也会跟着改变
    
    
      name:"Item",
      props:{
        todo:Object,
        index:Number,
        changeStatus:Function,
        dltO:Function,
      },
      data() {
        return {
          //定义一个状态
          isShow:false
        };
      },
    
      methods:{
        changeZt(){
          //点击单选框,更改状态
          this.changeStatus(this.index)
    
        },
    
        //点击删除按钮
        deleteO(){
          //给组价传递index
          this.dltO(this.index)
        }
      }
    
    
    };
    </script>
    
    <style scoped  lang="less">
    /*item*/
    
    .myClass{
      background-color: hotpink;
    }
    
    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;
    }
    
    </style>

    Footer组件

    <template>
      <div class="todo-footer">
        <label>
          <input type="checkbox"  v-model="ischeck" />
           <!-- isCheckAll的数据是和checked属性值进行关联的 -->
          <!-- 
            v-model 如果input当中是有value的,那么v-model影响的就是value的值
            对于文本输入框密码输入框来说一定是有value的
            对于单选输入框和多选输入框,如果没有写value,那么影响的的是checked的值
           --> 
        </label>
        <span> <span>已完成{{qcNum}}</span> / 全部{{qbNum}} </span>
        <button class="btn btn-danger"  @click="deleteQc">清除已完成任务</button>
      </div>
    </template>
    
    <script>
    export default {
    
      //1.父组件传递todos组件,计算已完成和全部数量
      // 2.对于全选按钮,需要判断两种情况,一种是获取,一种是修改
      // 对于获取逻辑,需要判断已完成数量和全部数量是否全等,
      //对于修改逻辑,则需要对遍历todos的每个对象,状态进行修改
      //3.对于清除已完成的任务,需要判断已经状态为true的对象清除
    
    
      name:'Footer',
      props:{
        todos:Array,
        delQc:Function,
      },
      data() {
        return {};
      },
    
      methods:{
        deleteQc(){
          //将新数组传递父组件,让父组件对原数组跟新
          let newTodos=  this.todos.filter(item =>!item.isOver)
          this.delQc(newTodos)
    
        }
      },
    
      // 计算属性,组件中没有的属性
    
      computed:{
        //计算完成的数量
        qcNum(){
          return this.todos.filter(item =>item.isOver).length
        },
    
        //计算全部的数量
        qbNum(){
          return this.todos.length
        },
    
        ischeck:{
          
          //获取方法
          get(){
            return  this.qcNum ===this.qbNum && this.qbNum>0
          },
    
          //修改方法
          set(value){
            //遍历todos,将每一项的isOver都随着vlaue改变
            this.todos.forEach(item =>item.isOver = value)
          }
        }
    
    
      }
    
    
    
    
    };
    </script>
    
    <style scoped  lang="less">
    
    /*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>

    将todos数据保存在localStorage

    localStorage的简介(永久存储,关闭和刷新浏览器,数据不会丢失)
    目前所有的浏览器中都会把localStorage的值类型限定为string类型,
    这个在对我们日常比较常见的JSON对象类型需要一些转换

    1.我们将对todos深度监视,如果todos的数据变化了,就会立刻存储在localStorage

    2.然后从data中获取存储在localStorage中的数据

    <template>
      <div class="todo-container">
        <div class="todo-wrap">
          <Header :todos="todos"  :recOne="recOne"></Header>
          <Main 
          :todos="todos"
          :changeStaus="changeStaus"
          :deleteOne="deleteOne"
          ></Main>
          <Footer 
            :todos="todos"
            :delet="delet"
          ></Footer>
         
         
        </div>
      </div>
    </template>
    
    
    <script>
    
    // 引入组件
    import Header  from '@/components/Header'
    import Main  from  '@/components/Main'
    import Footer  from  '@/components/Footer'
    let id = 0
    export default {
      //自定义todos
      //  todos:[
      //       {id:1,content:'抽烟', isOver:false},
      //       {id:2,content:'喝酒', isOver:true},
      //       {id:3,content:'烫头', isOver:false},
    
      //     ]
      name:'App',
      data(){
        return {
          todos: JSON.parse(window.localStorage.getItem('TODOS_KEY')) || []
        }
      },
      
       // 一般监视,当todos的数据只要发生变化,就会存储到localStorage
      //修改isOver状态,并不能存储在localStorage, 因为他修改的数组才会存储到localStorage
      // watch:{
      //   todos(newVal, oldVal){
      //     localStorage.setItem("TODOS_KEY", JSON.stringify(newVal))
      //   }
    
      // },
    
      // 深度监视,只有数组的数据变化了,包括对象元素的属性变化也会存储在localStorage
      watch:{
        todos:{
          deep:true,
          handler(newVal, oldVal){
            //赋值给localStorage
            localStorage.setItem('TODOS_KEY', JSON.stringify(newVal))
          },
    
        // 代表在wacth里声明了todos这个方法之后立即先去执行handler方法
        immediate: true
        }
      },
      
      methods:{
    
        //接收footer组件的数据,删除已有的数据
        delet(newTodos){
          this.todos= newTodos
        },
    
        //接收header组件的数据
         recOne(todo){
            // const length = this.todos.length  ? this.todos[this.todos.length - 1] : {id:1}
            // todo.id = ++length.id 
    
            todo.id = new Date()
           //数组添加一个新对象
           this.todos.unshift(todo)
    
         },
    
        //接收item组件的数据,更改单选框状态
         changeStaus(index){
           this.todos[index].isOver = !this.todos[index].isOver
         },
    
         //接收item组件数据,删除一个对象
         deleteOne(index){
           this.todos.splice(index,1)
         }
         
         
    
      },
    
    
    
      // 注册组件
      components:{
        Header,
        Main,
        Footer,
      }
    };
    
    </script>
    
    <style scoped  lang="less">
    /*app*/
    .todo-container {
      width: 600px;
      margin: 0 auto;
    }
    .todo-container .todo-wrap {
      padding: 10px;
      border: 1px solid #ddd;
      border-radius: 5px;
    }
    
    </style>

    3.

    todos: JSON.parse(localStorage.getItem("TODOS_KEY"))  || []
    如果是空的,浏览器会报错,那就搞个空数组
  • 相关阅读:
    通过5G网络释放触觉互联网的力量
    架构师的主要职责和一些误区
    Codeforces 305E Playing with String
    hdu3949:XOR
    bzoj1923: [Sdoi2010]外星千足虫
    bzoj1013: [JSOI2008]球形空间产生器sphere
    bzoj1770: [Usaco2009 Nov]lights 灯
    一些还没有写的AC自动机题
    bzoj2553: [BeiJing2011]禁忌
    bzoj1030: [JSOI2007]文本生成器
  • 原文地址:https://www.cnblogs.com/fsg6/p/13516426.html
Copyright © 2020-2023  润新知