vue3发布以来备受瞩目,与之起来的vite都是倍感神秘,在这里我们用一个todolist的小例子,来揭秘vue3+vite的面纱。
本文是在《Vite + Vue3 初体验 —— Vue3 篇》的启发下写的,由于原文的代码和过程有一些需要注意的坑点,在这里我们会把步骤详细的整理以及简单的优化。
创建项目
使用vite创建
npm init vite@latest
输入项目名 如 vue-todolist
vite可以构建多种框架的项目,这里选用vue
选用vue-ts的组合,如果你对ts还不熟,需要抓紧时间上车了
这样项目就创建好了,剩下就是装依赖和运行项目了
开始编写 todolist
为了项目开起来稍微美观一点,这里使用ant-design-vue的UI框架,另外框架的组件按需引入还需要使用(unplugin-vue-components)。
在项目里边安装:
// 按需引入插件
npm install unplugin-vue-components -D
// UI框架
npm install ant-design-vue@next --save
**这里可以用npm也可以用yarn,根据个人情况使用,本文全部使用npm方式
配置按需引入
上边安装了按需引入的插件,还需要进行配置,在vite.config.js中配置
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import Components from "unplugin-vue-components/vite"
import { AntDesignVueResolver } from "unplugin-vue-components/resolvers";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
Components({
resolvers: [
AntDesignVueResolver()
]
})
]
})
然后在main.ts中引入ant-design-vue的样式
基本结构
在components中创建TodoList.vue文件,并引入App.vue中,在TodoList.vue中编写基本todolist的结构:
TodoList.vue
<template>
<div class="todo-list-container" >
<div class="todo-wrapper" >
<input class="todo-input" placeholder="请输入待办项" />
<ul class="todo-list" >
<li class="todo-item" >
<span>Todo Items</span>
<div class="operator-list" >
<DeleteOutlined />
<CheckOutlined />
<ToTopOutlined />
</div>
</li>
<li class="todo-item" >
<span>Todo Items</span>
<div class="operator-list" >
<DeleteOutlined />
<CheckOutlined />
<ToTopOutlined />
</div>
</li>
<li class="todo-item todo-completed" >
<span>Todo Items</span>
<div class="operator-list" >
<CheckCircleFilled />
</div>
</li>
</ul>
</div>
</div>
</template>
<script setup lang="ts">
// Input组件
import {Input} from 'ant-design-vue';
// 图标组件
import { DeleteOutlined, CheckOutlined, CheckCircleFilled, ToTopOutlined } from "@ant-design/icons-vue";
</script>
<style scoped lang="less">
*{
padding: 0;
margin: 0;
}
.todo-list-container {
width: 100vw;
height: 100vh;
box-sizing: border-box;
padding-top: 100px;
background: linear-gradient(rgba(93, 190, 129, 0.02), rgba(125, 185, 222, 0.02));
display: flex;
justify-content: center;
.todo-wrapper {
width: 60vw;
.todo-input {
width: 100%;
height: 50px;
border: 2px solid rgba(255, 177, 27, 0.5);
border-radius: 5px;
padding-left: 10px;
font-size: 18px;
color: #f05e1c;
&::placeholder {
color: #f05e1c;
opacity: 0.4;
}
&:hover, &:focus {
border-color: #ffb11b;
box-shadow: 0 0 0 2px rgba(255, 177, 27, 0.2);
outline: none;
}
}
.todo-list {
margin-top: 20px;
list-style: none;
.todo-item {
margin-bottom: 10px;
padding: 15px 10px;
box-sizing: border-box;
border-bottom: 2px solid rgba(255, 177, 27, 0.3);
border-radius: 5px;
font-size: 16px;
color: #f05e1c;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
transition: all .5s;
&:hover {
box-shadow: 0 0 5px 8px rgba(255, 177, 27, 0.2);
border-bottom: 2px solid transparent;
}
// 完成列表样式
&.todo-completed {
color: rgba(199,199,199,1);
border-bottom-color: rgba(199,199,199,0.4);
&:hover {
box-shadow: none;
border-bottom-color: rgba(199,199,199,0.4);
}
}
// 置顶列表样式
&.todo-top {
box-shadow: none;
background-color: #f05e1c;
color: #fff;
}
// 操作列表
.operator-list {
display: flex;
justify-content: flex-start;
align-items: center;
&:first-child {
margin-right: 10px;
}
}
}
}
}
}
</style>
这里使用了less,vite搭建这套脚手架中,已经配置了less/sass,只需要安装即可:
npm install -D less less-loader
然后运行项目:
会得到上边的结构,如果你的有差异,不要慌张耐心查看自己的问题以及代码是否和文中一致,如果实在解决不了可以留言,也可以加博主微信文末有介绍。
然后就是逻辑部分的代码
先上完整的TodoList.vue组件代码
<template>
<div class="todo-list-container" >
<div class="todo-wrapper" >
<input
class="todo-input"
placeholder="请输入待办项"
v-model="todoText"
@keydown.enter="addTodoList"
/>
<ul class="todo-list" >
<li
v-for="(item, index) in todoList"
class="todo-item"
:class="{'todo-completed': item.is_completed, 'todo-top': item.is_top}"
>
<span>{{item.title}}</span>
<div class="operator-list" >
<CheckCircleFilled v-if="item.is_completed"/>
<ToTopOutlined v-if="!item.is_completed" @click="topTodoList(index)" />
<DeleteOutlined v-if="!item.is_completed" @click="deleteTodoList(index)" />
<CheckOutlined v-if="!item.is_completed" @click="completedTodoList(index)" />
</div>
</li>
</ul>
</div>
</div>
</template>
<script setup lang="ts">
// Input组件
import {Input} from 'ant-design-vue';
// 图标组件
import { DeleteOutlined, CheckOutlined, CheckCircleFilled, ToTopOutlined } from "@ant-design/icons-vue";
import { ref } from 'vue'
// 声明存储数据数组
// let todoList = ref<{
// title: string,
// is_completed: Boolean,
// is_top: Boolean
// }[]>([]);
// 上边采用了ts泛型结合的写法,也可以将类型分开
interface TodoType {
title: string,
is_completed: boolean,
is_top: boolean
};
let todoList = ref<TodoType[]>([]);
// 这里声明一个对数组进行排序的方法,在增删改查后对list进行排序
const todoListSort = (list: TodoType[]):TodoType[] => {
// 置顶的列表
let topList:TodoType[] = [];
// 完成的列表
let completedList:TodoType[] = [];
// 其他列表
let otherList:TodoType[] = [];
list.forEach(item => {
if(item.is_top){
topList.push(item);
}else{
if(item.is_completed){
completedList.push(item);
}else{
otherList.push(item);
}
}
});
return [...topList, ...otherList, ...completedList];
}
// 创建一个变量,用于输入框的绑定
const todoText = ref('');
// 这里ref看似没有使用泛型,实际上是省略了,上边的等于
// const todoText = ref<string>('');
// 然后是增加list
const addTodoList = () => {
// 如果input内容为空则不继续执行
if(!todoText.value) return;
// 将input的内容添加到todoList
todoList.value.unshift({
title: todoText.value,
is_completed: false,
is_top: false
});
// 添加完成后,清空todoText的值
todoText.value = '';
// 插入后排序
todoList.value = todoListSort(todoList.value);
}
// 删除List
const deleteTodoList = (index:number) => {
todoList.value.splice(index, 1);
}
// 完成List
const completedTodoList = (index:number) => {
todoList.value[index].is_completed = true;
// 修改后排序,将完成的放后边
todoList.value = todoListSort(todoList.value);
}
// 置顶列表list
const topTodoList = (index:number) => {
todoList.value[index].is_top = true;
// 置顶后排序,将完成的放前边
todoList.value = todoListSort(todoList.value);
}
</script>
<style scoped lang="less">
*{
padding: 0;
margin: 0;
}
.todo-list-container {
width: 100vw;
height: 100vh;
box-sizing: border-box;
padding-top: 100px;
background: linear-gradient(rgba(93, 190, 129, 0.02), rgba(125, 185, 222, 0.02));
display: flex;
justify-content: center;
.todo-wrapper {
width: 60vw;
.todo-input {
width: 100%;
height: 50px;
border: 2px solid rgba(255, 177, 27, 0.5);
border-radius: 5px;
padding-left: 10px;
font-size: 18px;
color: #f05e1c;
&::placeholder {
color: #f05e1c;
opacity: 0.4;
}
&:hover, &:focus {
border-color: #ffb11b;
box-shadow: 0 0 0 2px rgba(255, 177, 27, 0.2);
outline: none;
}
}
.todo-list {
margin-top: 20px;
list-style: none;
.todo-item {
margin-bottom: 10px;
padding: 15px 10px;
box-sizing: border-box;
border-bottom: 2px solid rgba(255, 177, 27, 0.3);
border-radius: 5px;
font-size: 16px;
color: #f05e1c;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
transition: all .5s;
&:hover {
box-shadow: 0 0 5px 8px rgba(255, 177, 27, 0.2);
border-bottom: 2px solid transparent;
}
// 完成列表样式
&.todo-completed {
color: rgba(199,199,199,1);
border-bottom-color: rgba(199,199,199,0.4);
&:hover {
box-shadow: none;
border-bottom-color: rgba(199,199,199,0.4);
}
}
// 置顶列表样式
&.todo-top {
box-shadow: none;
background-color: #f05e1c;
color: #fff;
}
// 操作列表
.operator-list {
display: flex;
justify-content: flex-start;
align-items: center;
&:first-child {
margin-right: 10px;
}
}
}
}
}
}
</style>
上边就是完整的代码,增加、完成和置顶使用排序,这里是练习时候为了达到一定的效果编写的,实际应用中要在增加和设置的地方单个操作更好,不然每次都给整个数据排序效率太低。
以上完成后如下图
以上就是本文全部内容,如对你有帮助欢迎点赞留言
如有疑问可以留言,也可以到QQ群一起探讨:
QQ群1: 657011407, QQ群2: 492593055,也可以到微信找我 shenzhipeng1023