快速写你的第一个vue3.0—Todolist吧~

前言

很多时候,当我们面对着新技术的到来,有些人看文档已经大概了解其中缘由,甚至已经能直接上手项目。但~是不是还会有一些刚入门的小伙伴,对于新技术可谓是又爱又恨。其实,不要害怕写错代码,要勇于尝试,要在错误的代码中寻找自己的薄弱点并攻破。加油,从写第一个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

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,请点赞保持关注噢。

最后别忘了点赞噢~

最后别忘了点赞噢~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值