vue3学习案例

一个ToolList案例

在这里插入图片描述
App.vue中

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <!-- <HelloWorld msg="Hello Vue 3.0 + Vite" /> -->
  <Todos></Todos> 
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'
 import Todos from './components/Todos.vue'

export default {
  name: 'App',
  components: {
    HelloWorld,
     Todos
  }
}
</script>

Todos.vue中:

<template>
  <div>
    <!-- 新增todo -->
    <input
      type="text"
      v-model="newTodo"
      @keyup.enter="addTodo"
      autofocus
      placeholder="新增进入待办"
      autocomplete="off"
    />

    <!-- todo列表 -->
    <ul>
      <li
        v-for="todo in filterdTodos"
        :key="todo.id"
        :class="{ completed: todo.completed, editing: todo === editedTodo }"
      >
      <div class="view">
        <input type="checkbox" v-model="todo.completed" />
        <label @dblclick="editTodo(todo)">{{ todo.title }}</label>
        <button @click="removeTodo(todo)">X</button>
      </div>
      <!-- 编辑代办 -->
      <input
        type="text"
        class="edit"
        v-model="todo.title"
        v-todo-foucs="todo===editedTodo"
        @blur="doneEdit(todo)"
        @keyup.enter="doneEdit(todo)"
        @keyup.escape="cancelTodo(todo)"
      />
      </li>
      
    </ul>
    <!-- 过滤 -->
    <p class="filters">
        <span @click="visibility='all'" :class="{selected:visibility==='all'}">ALL</span>
        <span @click="visibility='active'" :class="{selected:visibility==='active'}">Active</span>
        <span @click="visibility='completed'" :class="{selected:visibility==='completed'}">Completed</span>
    </p>
  </div>
</template>

<script>
import { reactive, toRefs ,computed,watchEffect} from "vue";
// 过滤器
const filters={
  all(todos){
    return todos
  },
  active(todos){
    return todos.filter(todo=>!todo.completed)
  },
  completed(todos){
      return todos.filter(todo=>todo.completed)
  },
}
// 缓存操作
const todoStorage={
  fetch(){
    let todos=JSON.parse(localStorage.getItem('vue3-todos')||'[]')
    todos.forEach((todo,index) =>{
      todo.id=index+1
    })
    return todos
  },
  save(todos){
     localStorage.setItem("vue3-todos",JSON.stringify(todos));
  }
}


// 存储操作

export default {
  setup() {
    const state = reactive({
      newTodo: "",
      todos: todoStorage.fetch(),//初始化
      beforeEditCache: '', //缓存编辑前的title
      editedTodo: null, // 正在编辑的todo
      visibility:'all',
      filterdTodos:computed(()=>{
       return filters[state.visibility](state.todos)
      })
    });
    function addTodo() {
      state.todos.push({
        id: state.todos.length + 1,
        title: state.newTodo,
        completed: false,
      });
      //   状态置空
      state.newTodo = "";
    }

    function removeTodo(todo) {
      state.todos.splice(state.todos.indexOf(todo), 1);
    }
    function editTodo(todo) {
      state.beforeEditCache = todo.title;
      state.editedTodo = todo;
    }
    function cancelTodo(todo) {
      todo.title = state.beforeEditCache;
      state.editedTodo = null;
    }

    function doneEdit(todo) {
      state.editedTodo = null;
    }

    watchEffect(()=>{
      todoStorage.save(state.todos)
      
    })


    return {
      ...toRefs(state),
      addTodo,
      removeTodo,
      editTodo,
      cancelTodo,
      doneEdit,
    };
  },
  directives:{
      "todo-foucs":(el,{value},vnode)=>{
          if(value){
              el.focus();
          }
      }
  }
};
</script>

<style  scoped>
.completed label {
  text-decoration: line-through;
}
.edit,
.editing .view {
  display: none;
}
.view,
.editing .edit {
  display: block;
}
.filters >span{
  padding:2px 4px;
  margin-right: 4px;
  border: 1px solid transparent;
}
.filters >span.selected{
  border-color: rgba(173,47,47,0.2);
}
</style>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值