Vue3+Vite实现TodoList

Vite官网:开始 | Vite 官方中文文档镜像

Vuex官网:Vuex 是什么? | Vuex

 本文章有用到Vue3+Vite+Vuex相关技术,不懂的地方可以查看相关文档。

使用Vite创建Vue3项目相关npm yarn 在此不多演示,此文章提供相关技术代码,安装方式可见Vue官方文档。

 

 上图为创建完项目的目录和Vuex官网基本思想(其中store为自行创建,因为要用Vuex)

Vuex的五种属性,基本用法:

   1、state: vuex的基本数据,用来存储变量;
   2、getters: 从基本数据(state)派生的数据,相当于state的计算属性;
   3、mutations: 提交更新数据的方法,是同步的(异步使用action)。
   4、action: 可以异步,但不能直接操作State
   5、modules: Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的         state、mutation、action、getter。

 项目截图

接下来在store内创建index.js

store/index.js

// const { createStore } = require("vuex");

const store = createStore({
  state: {
    todos: [
      {
        id: 1,
        title: '抽烟',
        done: true,
      },
      {
        id: 2,
        title: '喝酒',
        done: false,
      },
      {
        id: 3,
        title: '打麻将',
        done: false,
      },
    ],
    state: 'all',
    visible: 'all',
  },
  getters: {
    all(state) {
      return state.todos;
    },
    active(state) {
      return state.todos.filter((todo) => !todo.done);
    },
    done(state) {
      return state.todos.filter((todo) => todo.done);
    },
    filterTodo(state) {
      if (state.state == 'all') {
        return state.todos;
      } else if (state.state == 'active') {
        return state.todos.filter((todo) => !todo.done);
      } else if (state.state == 'complete') {
        return state.todos.filter((todo) => todo.done);
      }
    },
  },

  mutations: {
    createTodo(state, payload) {
      console.log(state, payload);
      state.todos.push(payload);
    },
    removeTodo(state, payload) {
      state.todos = state.todos.filter((todo) => todo.id != payload.id);
    },
    clearTodo(state, payload) {
      let todos = state.todos;
      for (let index = todos.length - 1; index >= 0; index--) {
        const todo = todos[index];
        if (todo.done) {
          todos.splice(index, 1);
        }
      }
    },
    changeTodo(state, payload) {
      state.state = payload;
      state.visible = payload;
      console.log('state.visible', state.visible);
    },
  },
  actions: {
    removeTodo({ commit }, payload) {
      setTimeout(() => {
        commit('removeTodo', payload);
      }, 100);
    },
  },
});

export default store;

App.vue(在App.vue中引用组件)

<template>
  <div id="todoapp">
    <todo-header />
    <div class="content">
      <!-- <todo-create @createTodo="createTodo"/> -->
      <todo-create :createTodo="createTodo" />
      <todo-list :todos="todos" />
      <todo-footer :todos="todos" :clearDone="clearDone" />
    </div>
  </div>
</template>

<script setup>
import { computed, provide } from '@vue/runtime-core';
import { useStore } from 'vuex';
const store = useStore();

let todos = computed(() => store.getters.filterTodo);
console.log(todos);

const createTodo = (title) => {
  console.log('createTodo', title);
  const todo = {
    id: Math.random(),
    title,
    done: false,
  };
  store.commit('createTodo', todo);
};

const deleteTodo = (id) => {
  store.dispatch('removeTodo', { id });
};

const clearDone = () => {
  store.commit('clearTodo');
};

console.log(todos);
provide('deleteTodo', deleteTodo);
</script>

<style scoped></style>

 Components/TodoCreate.vue(用来显示输入框)

<template>
  <div id="create-todo">
    <input
      id="new-todo"
      placeholder="请输入任务,按回车键确认"
      autocomplete="off"
      type="text"
      v-model="newTodo"
      @keyup.enter="handleCreateTodo"
    />
  </div>
</template>

<script setup>
let newTodo = ref('')

let props = defineProps({
    createTodo: Function,
})

const handleCreateTodo = ()=>{
  console.log('props',props);
    let title = newTodo.value.trim()
    if (title.length > 0) {
        console.log("handleCreateTodo", title);
        props.createTodo(title);
        newTodo.value = "";
      } else {
        alert("输入不能为空");
      }
}

</script>

<style lang="scss" scoped>
</style>

Components/TodoHeader(只用来显示头部Todos)

<template>
  <div class="title">
    <h1>Todos</h1>
  </div>
</template>

<script>
export default {
  // name: "TodoHeader",
  setup() {
    return {};
  },
};
</script>

<style scoped>
</style>

Components/TodoList(引用todoItem展示todos信息)

<template>
  <ul id="todo-list">
    <todo-item v-for="todo in todos" :key="todo.id" :todo="todo"> </todo-item>
  </ul>
</template>

<script setup>
defineProps({
  todos:Array,
});
</script>

<style lang="scss" scoped>
</style>

Components/TodoItem.vue(展示添加的todos信息)

<template>
  <li>
    <div class="todo" :class="{ done: todo.done }">
      <div class="display">
        <input class="check" type="checkbox" v-model="todo.done" />
        <div class="todo-content">{{ todo.title }}</div>
        <span class="todo-destroy" @click="handleDeleteTodo(todo.id)"></span>
      </div>
    </div>
  </li>
</template>

<script setup>

const deleteTodo = inject('deleteTodo')

const props = defineProps({
  todo: Object,
});

const handleDeleteTodo = (id) => {
  deleteTodo(id);
};
</script>

<style lang="scss" scoped>
</style>

Components/TodoFooter.vue(显示底部信息,展示未完成已完成的,清除全部已完成的)

<template>
  <div id="todo-stats">
    <span class="todo-count">
      <span class="number">{{ undone }}</span>
      <span class="word">项待完成</span>
    </span>
    <span class="todo-filter">
      <todo-filter />
    </span>
    <span>
      <Status></Status>
    </span>
    <span class="todo-clear">
      <a @click="clearDone()">
        Clear <span>{{ done }}</span> 已完成事项
      </a>
    </span>
  </div>
</template>

<script setup>
import { computed } from '@vue/runtime-core';
const props = defineProps({
  todos: {
    type: Array,
    required: true,
  },
  clearDone: Function,
  changeStatus: Function,
});

const done = computed(() => {
  return props.todos.filter((item) => item.done == true).length;
});

const undone = computed(() => {
  return props.todos.filter((item) => item.done == false).length;
});
</script>

<style lang="scss" scoped></style>

Components/State.vue(用来显示全部、未完成、已完成。)

<template>
  <a>
    <span
      @click="changeStatus('all')"
      :class="{ active: store.state.visible == 'all' }"
    >
      全部
    </span>
    <span
      @click="changeStatus('active')"
      :class="{ active: store.state.visible == 'active' }"
      >未完成</span
    >
    <span
      @click="changeStatus('complete')"
      :class="{ active: store.state.visible == 'complete' }"
      >已完成</span
    >
  </a>
</template>

<script setup>
import { computed, provide } from '@vue/runtime-core';
import { useStore } from 'vuex';
const store = useStore();
let visible = store.state.visible;
const changeStatus = (state) => {
  store.commit('changeTodo', state);
  visible = state;
  console.log(store.state.visible);
};
const props = defineProps({
  changeStatus: Function,
});
</script>

<style scoped>
span {
  padding: 7px;
  padding-left: 10px;
  padding-right: 10px;
  border: 1px solid white;
  margin-left: 2px;
}
span:nth-child(1) {
  margin-left: 70px;
}
span:hover {
  cursor: pointer;
  border: 1px solid rgb(187, 187, 187);
  border-radius: 10px;
  background-color: rgb(244, 244, 244);
}
.active {
  border: 1px solid rgb(187, 187, 187);
  border-radius: 10px;
  background-color: rgb(244, 244, 244);
}
</style>

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值