项目准备
使用vite创建并且初始化项目
npm create vite
如果没有安装vite需要先安装vite
npm install vite
然后再在终端执行第一个命令使用vite创建项目
执行npm create vite后会出现以下选项
// 项目名称
√ Project name: ... todolist
// 选择框架,这里选vue
? Select a framework: » - Use arrow-keys. Return to submit.
Vanilla
> Vue
React
Preact
Lit
Svelte
Others
// 选择JavaScript,你也可以选择TypeScript,推荐选择TS
? Select a variant: » - Use arrow-keys. Return to submit.
> JavaScript
TypeScript
Customize with create-vue ↗
Nuxt ↗
然后在终端中分别键入以下命令
// 进入项目文件夹
cd todolist
// 安装vite默认的依赖
npm install
// 打开本地服务器
npm run dev
然后你会看到下面这个选项
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
➜ press h to show help
点击http://localhost:5173/就能在浏览器中看到项目了
安装项目所需要的依赖(dependencies)
npm install tailwindcss postcss autoprefixer -D
编写配置文件
// 在项目根目录下找到vite.config.js,如果没有就自己创建一个
// 在vite.config.js进行配置
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import autoprefixer from 'autoprefixer'
import tailwindcss from 'tailwindcss'
export default defineConfig({
// 服务器配置,可以忽略
server:{
// 自动打开浏览器
open:true;
// 更改端口号,vue默认本地服务器端口号是5173
port:5000;
},
// css配置
css:{
// PostCSS是一个灵活的CSS处理工具,可以通过插件实现语法转换、前缀添加等操作。
postcss:{
plugins:[
// Autoprefixer可以为CSS属性自动添加浏览器厂商前缀。
autoprefixer({
// 浏览器版本设置
overrideBrowserslist: [
"last 2 versions",
"ie >= 9",
]
}),
// tailwindcss配置,这里的配置比较简单,如果有更复杂的配置建议建立一个
// 单独的tailwind.config.js配置文件俩编写配置信息
tailwindcss({
content:['./index.html',''./src/**/*.vue]
})
]
}
}
})
删除默认文件
- HelloWorld.vue
- 清空APP.vue,添加如下代码
<template></template>
<script>
// 其他代码
</script>
- 清空stlye.css文件,添加如下代码
@tailwind base;
@tailwind componets;
@tailwind utilities;
/* 导入reset样式 */
@layer base{
*,
*::before,
*::after {
box-sizing: border-box
}
body,
h1,
h2,
h3,
h4,
p,
figure,
blockquote,
dl,
dd {
margin: 0
}
ul[role="list"],
ol[role="list"] {
list-style: none
}
html:focus-within {
scroll-behavior: smooth
}
body {
min-height: 100vh;
text-rendering: optimizeSpeed;
line-height: 1.5
}
a:not([class]) {
text-decoration-skip-ink: auto
}
img,
picture {
max-width: 100%;
display: block
}
input,
button,
textarea,
select {
font: inherit
}
@media(prefers-reduced-motion:reduce) {
html:focus-within {
scroll-behavior: auto
}
*,
*::before,
*::after {
animation-duration: .01ms !important;
animation-iteration-count: 1 !important;
transition-duration: .01ms !important;
scroll-behavior: auto !important
}
}
}
编写组件
- 在components文件夹中创建两个SFC文件:Search.vue,List.vue,键入以下代码
<template>
<!-- 其他html代码-->
</template>
<script>
export default{
// 其他代码
}
</script>
- 编辑App.vue
<template>
<div class="todoWrapper">
<div class="todoheader">
<h5>Todo List</h5>
<div class="add">
<input
placeholder="some todo"
type="text">
<button>Add</button>
</div>
</div>
<!-- 自定义组件 -->
<Search/>
<List/>
<div class="todoheader">
<span>DoneTodo:</span>
<span>Todo:</span>
</div>
</div>
</template>
<script>
// 引入需要List和Search组件
import List from './components/List.vue'
import Search from './components/Search.vue'
</script>
在浏览器网页中你会看到
添加适当的样式
<div class="todoWrapper w-full flex flex-col items-center">
<div class="todoheader w-full flex flex-col items-center">
<h5 class="text-3xl mt-4 mb-4 text-slate-300">Todo List</h5>
<div class="add w-1/2">
<input
class="w-3/4 pl-2 py-0 border-0 rounded h-8 text-xl"
placeholder="some todo"
type="text">
<button
class="ml-2 h-8 py-0 px-2 text-xl rounded-xl border-0"
>Add</button>
</div>
</div>
<!-- 自定义组件 -->s
<Search/>
<List/>
<div class="todoheader w-1/2 flex flex-col">
<span>DoneTodo:</span>
<span>Todo:</span>
</div>
</div>
添加样式后的todolist
3. add Todo
// App.vue <script>标签中添加如下代码
data() {
// 添加子组件
components:{Search,List}
return {
todos: [],
searchValue: '',
todo: ''
}
},
mounted() {
this.todos = localStorage.getItem('todos')
? JSON.parse(localStorage.getItem('todos'))
: []
},
methods: {
// 将todo存储到localStorage中
saveLocalStorage() {
localStorage.setItem('todos', JSON.stringify(this.todos))
},
// 添加todo
addTodo() {
// 每一个todo有两个属性:todo内容以及todo是否完成
this.todos.unshift({
activity: this.todo,
isDone: false
})
// 更新locaStorage中的todos数组
this.saveLocalStorage()
this.todo = ''
}
}
// App.vue <template>标签中修改如下代码
<input v-model="todo" @keyup.enter="addTodo" class="w-3/4 pl-2 py-0 border-0 rounded h-8 text-xl" placeholder="some todo" type="text">
<button @click="addTodo" class="ml-2 h-8 py-0 px-2 text-xl rounded-xl border-0">Add</button>
localStorage中的todos数组
4. 编写List.vue组件,显示所有todo
<template>
<div class="list">
<ul>
<li v-for="(todo,index) in todos" :key="index">
{{ todo.activity }}
<button>{{ todo.isDone }}</button>
<button>Delete</button>
</li>
</ul>
</div>
</template>
<script>
export default{
props:{
todos:{
type:Array,
default:[]
}
}
}
</script>
// 修改App.vue中的List组件
// 这里用到了props进行组件之间的信息传递
<List :todos="todos"/>
修改list样式
<div class="list w-full mt-2">
<ul class="w-full flex flex-col items-center">
<li
v-for="(todo,index) in todos"
:key="index"
class="w-1/2 flex flex-row justify-start">
<span class="w-3/4 bg-violet-200 mb-1 pl-2 py-1 rounded">{{ todo.activity }}</span>
<div class="ml-2 mb-1">
<button class="mr-2 p-1 rounded bg-cyan-500">{{ todo.isDone }}</button>
<button
class=" bg-cyan-500 p-1 rounded">Delete</button>
</div>
</li>
</ul>
</div>
修改后todolist的样式
在App.vue添加函数
computed:{
doneTodo(){
return this.todos.filter(item=>item.isDone).length
},
stillTodo(){
return this.todos.filter(item=>!item.isDone).length
}
},
// 修改<template>内的代码
<span>DoneTodo:{{ doneTodo }}</span>
<span>Todo:{{ stillTodo }}</span>
5. 添加删除todo功能
// App.vue的export default 的对象中的methods添加如下代码
methods:{
deleteTodo(delteIndex){
this.todos=this.todos.filter((item,index)=>{
if(index!==delteIndex) return item
})
this.saveLocalStorage()
}
}
// 修改App.vue中的List组件
<List :todos="todos" @delete-todo="deleteTodo"/>
// List添加如下代码
methods:{
deleteTodo(index){
// this.$emit也是组件间进行通信的一种方式,通过发出自定义事件进行通信
this.$emit('deleteTodo',index)
}
}
// list <template>中进行如下修改
<button
@click="deleteTodo(index)"
class=" bg-cyan-500 p-1 rounded">Delete</button>
现在点击delete就可以删除todo啦
- 编写Search组件
<template>
<div class="search my-2 w-1/2 flex flex-col-reverse justify-end">
<input
v-model.trim="search"
@keyup="searchTodo(search)"
class="w-1/2 ml-80 rounded pl-2" type="text" placeholder="Search your todo">
</div>
</template>
<script>
export default{
data(){
return{
search:''
}
},
methods:{
searchTodo(search){
search = search.toLowerCase()||search
this.$emit('searchTodo',search)
}
}
}
</script>
// App.vue中添加如下代码
// computed中添加
displayTodo(){
const display = this.todos.filter(item=>
item.activity.includes(this.searchValue)||item.activity.toLowerCase().includes(this.searchValue)
)
return display
}
// methods中添加
searchTodo(searchVal){
this.searchValue = searchVal
}
// 修改App.vue中的search组件
<Search @search-todo="searchTodo"/>
- 添加功能,todo完成则DONE按钮发生变化
// List.vue中的 methods添加代码
doneTodo(index){
this.$emit('doneTodo',index)
const donebutton= this.$refs[`donebutton-${index}`][0]
if(this.todos[index].isDone){
donebutton.classList.add('line-through')
}else if(donebutton.classList.contains('line-through')){
donebutton.classList.remove('line-through')
}
// 修改List.vue <template>中的代码
<button
:ref="`donebutton-${index}`"
@click="doneTodo(index)"
class="mr-2 p-1 rounded bg-cyan-500">DONE</button>
// App.vue methods添加如下代码
doneTODO(doneIndex){
this.todos = this.todos.filter((item,index)=>{
if(index===doneIndex) item.isDone=!item.isDone
return item
})
}
// 修改App.vue的List组件
<List :todos="displayTodo" @delete-todo="deleteTodo" @done-todo="doneTODO"/>
效果展示 点击DONE,DONE中间会有一条横线
技术栈
vue + vite + tailwindcss