vue项目如何搭建(Vue项目实战——实现一个任务清单【基于 Vue3.x 全家桶(简易版)】)
导读:Vue3.x 项目实战(一) 内容 参考链接 Vue2.x全家桶 Vue2.x 全家桶参考链接 Vue2.x项目(一) Vue2.x 实现一个任务清单 Vue2.x项目(二...
Vue3.x 项目实战(一)
内容 参考链接 Vue2.x全家桶 Vue2.x 全家桶参考链接 Vue2.x项目(一) Vue2.x 实现一个任务清单 Vue2.x项目(二) Vue2.x 实现GitHub搜索案例 Vue3.x项目(三) Vue3.x 实现一个任务清单Vue3.x 实现 todoList
1 、前言
如果你对 vue3 的基础知识还很陌生 ,推荐先去学习一下 vue 基础
内容 参考链接 Vue2.x全家桶 Vue2.x全家桶参考链接 Vue3.x的基本使用 Vue3.x基本使用参考链接 如果你 刚学完 vue3 基础知识 ,想检查一下自己的学习成果 如果你 已学完 vue3 基础知识 ,想快速回顾复习 如果你 已精通 vue3 基础知识 ,想做个小案例 那不妨看完这篇文章 ,我保证你一定会有收获的!2 、项目演示(一睹为快)
Vue3.x_任务清单
3、涉及知识点
麻雀虽小 ,五脏俱全 ,接下来开始我们的项目之旅吧~~
Vue3.x基础:插值语法 ,常用指令 ,键盘事件,列表渲染 ,计算属性 ,生命周期 Vue3.x进阶:props(父传子),自定义事件(任意组件间通信) Vuex4.x:状态管理库的使用 Vue-router4.x:使用路由进行页面跳转备注:
任意组件间的通信方式有很多种(全局事件总线 ,消息订阅预发布…) ,熟练掌握一种即可(推荐自定义事件,配置简单 ,容易理解) 本文是 vue 基础的练习项目 ,也涉及 vue 周边(Vuex ,Vue-Router)4 、项目详情
main.js
导入 store 和 router ,并且使用 import { createApp } from vue import App from ./App.vue import router from ./router import store from ./store createApp(App).use(store).use(router).mount(#app)./router/index.js
配置路由 直接导入 VS 按需导入(节约性能) 使用了 history 路由模式 import { createRouter, createWebHistory } from vue-router // 直接引入 import Start from ../views/Start.vue const routes = [ { path: /, name: Start, component: Start }, { path: /home, name: Home, // 按需引入 ,节约性能 component: () => import(../views/Home.vue) } ] // 创建路由对象 const router = createRouter({ history: createWebHistory(process.env.BASE_URL), routes }) export default router./store/index.js
state 中定义初始化数据 mutations 中定义方法 import { createStore } from vuex export default createStore({ // 定义初始化状态 state: { list: [ { title: "吃饭", complete: false, }, { title: "睡觉", complete: false, }, { title: "敲代码", complete: true, }, ] }, // 同步修改 state 都是方法 // 第一个参数 state 第二个参数是需要修改的值 mutations: { // 添加任务 addTodo(state, payload) { state.list.push(payload) }, // 删除任务 delTodo(state, payload) { state.list.splice(payload, 1) }, // 清除已完成 clear(state, payload) { // 把过滤之后的数组传进来 state.list = payload } }, // 异步提交 mutation // 第一个参数是 store 第二个参数是修改的值 actions: { }, // 模块化 modules: {} })App.vue 组件
做呈现的组件 <router-view /> 呈现内容 <template> <router-view/> </template> <style lang="scss"> * { margin: 0; padding: 0; } </style>Start.vue 组件
初始化页面 点击开启任务 ,跳转到任务页面 <template> <div class="title"> <h1>欢迎来到前端杂货铺</h1> <button @click="start">开始任务</button> </div> </template> <script> import { ref } from "vue"; import { useRouter } from "vue-router"; export default { name: "Start", setup() { // router 是全局路由对象 let router = useRouter(); let name = ref(10); // 点击进行路由跳转 let start = () => { router.push({ name: "Home", params: { name: name.value, }, }); }; return { start, }; }, }; </script> <style lang="scss" scoped> .title { color: orange; text-align: center; margin-top: 20%; } button { margin-top: 20px; width: 100px; height: 50px; background: skyblue; color: white; font-weight: bold; font-size: 15px; cursor: pointer; } button:hover { font-weight: bold; background: white; color: skyblue; cursor: pointer; } </style>Home.vue 组件
其他组件 表演的舞台 传递数据 自定义事件 ,进行组件间通信 <template> <div class="container"> <nav-header @add="add"></nav-header> <nav-main :list="list" @del="del"></nav-main> <nav-footer :list="list" @clear="clear"></nav-footer> </div> </template> <script> import NavHeader from "@/components/navHeader/NavHeader"; import NavMain from "@/components/navMain/NavMain"; import NavFooter from "@/components/navFooter/NavFooter"; import { ref, computed } from "vue"; import { useStore } from "vuex"; export default { name: "Home", // 接收父组件的数据 props: {}, // 定义子组件 components: { NavHeader, NavMain, NavFooter, }, // 接收的数据 ,上下文 setup(props, ctx) { let store = useStore(); let list = computed(() => { return store.state.list; }); let value = ref(""); // 添加任务 let add = (val) => { value.value = val; // 任务存在 不能重复添加 let flag = true; list.value.map((item) => { if (item.title === value.value) { // 有重复任务 flag = false; alert("任务已存在"); } }); // 没有重复任务 if (flag == true) { // 调用 mutation store.commit("addTodo", { title: value.value, complete: false, }); } }; // 删除任务 let del = (val) => { // 调用删除的 mutation store.commit(delTodo, val) console.log(val); } // 清除已完成 let clear = (val) => { store.commit(clear, val) } return { add, list, del, clear }; }, }; </script>NavHeader.vue 组件
头部组件(输入框) 输入任务按下回车进行任务的添加 emit ,使用分发的事务 <template> <div> <div class="container"> <input type="text" placeholder="请输入任务名称" v-model="value" @keyup.enter="enter" /> </div> </div> </template> <script> import { ref } from "vue"; export default { name: "navHeader", // 接收的数据,上下文 setup(props, ctx) { let value = ref(""); // 按回车键确认 let enter = () => { // 把输入框的内容传递给父组件 ctx.emit("add", value.value); // 清空输入框 value.value = ""; }; return { value, enter, }; }, }; </script> <style lang="scss" scoped> .container { text-align: center; margin-top: 220px; } .container input { height: 25px; width: 200px; margin-bottom: 10px; } </style>NavMain.vue 组件
props 接收 list 数据 v-for 遍历出来内容 使用条件判断做呈现 <template> <div class="container"> <div v-if="list.length > 0"> <div v-for="(item, index) in list" :key="index"> <div class="item"> <input type="checkbox" v-model="item.complete" /> {{ item.title }} <button class="del" @click="del(item, index)">删除</button> </div> </div> </div> <div v-else> 暂无任务 </div> </div> </template> <script> export default { name: "navMain", props: { list: { type: Array, required: true, }, }, // 分发事件的属性名 emits: ["del"], setup(props, ctx) { // 删除任务 let del = (item, index) => { ctx.emit("del", index); console.log(index, item); }; return { del, }; }, }; </script> <style lang="scss" scoped> .container { margin: auto; border: 2px solid #ccc; width: 200px; margin-bottom: 20px; } .item { height: 35px; line-height: 35px; position: relative; width: 200px; button { cursor: pointer; position: absolute; right: 4px; top: 6px; display: none; z-index: 99; } &:hover { background: #ddd; button { display: block; } } } </style>NavFooter.vue 组件
过滤出已完成的任务 ,获取到已完成任务的个数 过滤出未完成的任务 ,清除的时候保留未完成的任务 <template> <div class="container"> 已完成 {{ isCompelete }} / 全部 {{ list.length }} <span v-if="isCompelete" class="btn"> <button @click="clear">清除已完成</button> </span> </div> </template> <script> import { computed } from "vue"; export default { name: "navFooter", props: { list: { type: Array, required: true, }, }, setup(props, ctx) { let isCompelete = computed(() => { // 过滤已完成 let arr = props.list.filter((item) => { return item.complete; }); return arr.length; }); // 清除已完成 let clear = () => { // 过滤未完成的 let arr = props.list.filter((item) => { return item.complete === false; }); ctx.emit("clear", arr); console.log("clear"); }; return { isCompelete, clear, }; }, }; </script> <style lang="scss" scoped> .container { text-align: center; } </style>至此,此项目就实现了 ,如果什么问题 ,欢迎评论区或私信留言,看到定会第一时间解决!
5 、写在最后的话
如果你是 看完全篇 阅读到了这里 ,我相信你一定是有收获的!
那么下面不妨打开自己的电脑 ,启动自己的编译器 ,来跟着做 / 自己做一遍吧!
有机会的话 ,在不久的将来还会对这个小案例进行升级(功能以及样式的升级)敬请期待吧~~
6 、附源码
声明:本站所有文章 ,如无特殊说明或标注 ,均为本站原创发布 。任何个人或组织 ,在未征得本站同意时 ,禁止复制 、盗用 、采集 、发布本站内容到任何网站 、书籍等各类媒体平台 。如若本站内容侵犯了原著者的合法权益 ,可联系我们进行处理。
创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!