前言
很多时候,当我们面对着新技术的到来,有些人看文档已经大概了解其中缘由,甚至已经能直接上手项目。但,是不是还会有一些刚入门的小伙伴,对于新技术可谓是又爱又恨。其实,不要害怕写错代码,要勇于尝试,要在错误的代码中寻找自己的薄弱点并攻破~ 加油,从写第一个todolist开始吧。
写给你们同时也是写给自己的一句话:快速成长的捷径就是勇于面对自己的薄弱点。
了解相关Api
setup
- 大体介绍:setup 函数只执行一次,但后续对于数据的更新也依旧可以驱动视图更新.
- 执行顺序:setup函数会在 beforeCreate之后 created之前执行.
- 接收参数:props、context.
setup(props,context){
console.log('props',props) // 组件参数
console.log('context',context) // 上下文对象
// context.slots
// context.emit
// context.refs
}
reactive
- 用于获取一个对象的响应性代理对象,等价于 Vue.observable () API,经过reactive处理后的函数能变成响应式的数据,某种程度来说,类似于option api里面的data属性的值.
setup() {
// 这个类似于vue2中的data()返回的响应式对象
const count = reactive({ count: 0 })
return {
count
}
}
ref
- 将给定的值创建一个响应式的数据对象.
setup() {
const count = ref(0);
function increment() {
count.value++;
}
return {
count,
increment
}
}
computed
- 有时我们需要依赖于其他状态的状态——在 Vue 中,这是通过计算属性来处理的。 要直接创建一个计算值,我们可以使用computed.
const state = reactive({
count: 0,
plusOne: computed(() => state.count + 1)
})
- 创建可读可写的计算属性
// 创建一个响应式数据
const count = ref(1)
// 根据count的值创建一个响应式的计算属性, 它会根据ref自动计算并且返回一个新的ref
const computedCount = computed({
get: () => count.value + 1,
set: (val) => count.value = val - 1
} )
computedCount.count = 6
console.log(count.value) // 打印 5
watchEffect
- 副作用函数,如果需要在响应式数据发生变化的时候做某件事,我们会可以使用 effect 函数.
- 这个函数在读取 count.value 的时候会收集它作为依赖.
setup() {
const count = ref(0)
const add = () => count.value++
watchEffect(()=>{
console.log('count changed', count.value)
})
return { count, add }
}
编写Todolist
image
html部分
<template>
<div class="todo">
<div class="todo-form">
<div class="todo-input">
<input @keyup.enter="handleAddList" v-model="contentRef" type="text" placeholder="请输入事项内容" />
</div>
<button type="button" @click="handleAddList">添加事项</button>
</div>
<ul class="list" v-if="listRev.length">
<li class="list-item" v-for="(item,index) of listRev" :id="item.id" :key="item.id">
<div class="item-label" :class="item.status?'done':''">{{item.title}}</div>
<div class="action-btn">
<button class="success" v-if="!item.status" @click="handleStatusChange(index,true)">完成</button>
<button class="reset" v-if="item.status" @click="handleStatusChange(index,false)">激活</button>
<button class="delete" @click="handleRemove(index)">删除</button>
</div>
</li>
</ul>
<p v-else>暂无待办事项..</p>
</div>
</template>
全部代码
<template>
<div class="todo">
<div class="todo-form">
<div class="todo-input">
<input @keyup.enter="handleAddList" v-model="contentRef" type="text" placeholder="请输入事项内容" />
</div>
<button type="button" @click="handleAddList">添加事项</button>
</div>
<ul class="list" v-if="listRev.length">
<li class="list-item" v-for="(item,index) of listRev" :id="item.id" :key="item.id">
<div class="item-label" :class="item.status?'done':''">{{item.title}}</div>
<div class="action-btn">
<button class="success" v-if="!item.status" @click="handleStatusChange(index,true)">完成</button>
<button class="reset" v-if="item.status" @click="handleStatusChange(index,false)">激活</button>
<button class="delete" @click="handleRemove(index)">删除</button>
</div>
</li>
</ul>
<p v-else>暂无待办事项..</p>
</div>
</template>
<script lang="ts">
import { reactive, ref, watchEffect } from "vue";
// 事项接口
interface IList {
id: number;
title: string;
status: boolean;
}
export default {
setup() {
let listRev = reactive<Array<IList>>([]);
let contentRef = ref<string | null>(null);
let idRef = ref<number>(0);
// 事项添加
const handleAddList = () => {
if (!contentRef.value) return alert("请输入事项内容");
if (listRev.find((item) => item.title === contentRef.value)) {
return alert("该事项已存在,请输入其他事项吧~");
}
listRev.push({
title: contentRef.value,
id: ++idRef.value,
status: false,
});
contentRef.value = "";
};
// 事项完成
const handleStatusChange = (index: number, status: boolean) => {
listRev[index].status = status;
};
// 事项删除
const handleRemove = (index: number) => {
listRev.splice(index, 1);
};
const count = ref(0);
const add = () => count.value++;
watchEffect(() => {
console.log("contentRef changed", contentRef.value);
});
return {
listRev,
contentRef,
handleAddList,
handleStatusChange,
handleRemove,
};
},
};
</script>
<style lang="scss">
button {
border-width: 0px;
border-radius: 3px;
background: #1e90ff;
cursor: pointer;
outline: none;
font-family: Microsoft YaHei;
color: white;
font-size: 14px;
}
.todo {
padding: 5vw;
.todo-form {
display: flex;
justify-content: space-between;
.todo-input {
width: 75%;
text-align: left;
input {
width: 100%;
border: 1px solid #ccc;
padding: 10px 0px;
border-radius: 3px;
padding-left: 5px;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
}
input:focus {
border-color: #66afe9;
outline: 0;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),
0 0 8px rgba(102, 175, 233, 0.6);
}
}
button {
width: 20%;
font-size: 12px;
}
button:active {
background: #5599ff;
}
}
.list {
text-align: left;
vertical-align: top;
background: #fff;
color: rgb(30, 144, 255);
border-radius: 5px;
padding: 1em;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);
margin-top: 30px;
.list-item {
list-style: none;
padding: 10px 0;
border-bottom: 1px solid #eee;
display: flex;
justify-content: space-between;
.item-label {
width: 80%;
}
.action-btn {
width: 15%;
button {
margin: 0px 3px 5px;
font-size: 12px;
padding: 3px 7px;
}
.success {
background-color: #009688;
}
.delete {
background-color: #e91e63;
}
.reset {
background-color: #03a9f4;
}
}
}
.list-item:last-of-type {
border-bottom: none;
}
.done {
text-decoration: line-through;
color: #ddd;
}
}
}
</style>
写在最后
- 感谢能花费自己宝贵的时间看完这篇文章的读者们。
- 开始动手写你的todolist吧,别犹豫了~
- 后续会继续更新vue3相关的新api,请点赞保持关注噢。
最后别忘了点赞噢~
最后别忘了点赞噢~