日常总结:三个Demo

120 阅读3分钟

Promise封装一个弹窗

promise是什么呢?我对他的理解就是当一件事情的发生,你不确定结果时,peomise可以帮你处理。

那么当一个弹窗出现,你不知道用户会点击确认还是取消,这个时候就可以用promise来处理

我们先来预想一下这个弹窗已经封装好了我们应该怎么去用它,

const m = new myMadel()

m.show({title="我的弹窗",content="今晚打老虎"}).then(res=>{...点击确认做的事情}).catch(res=>.....点击取消做的事情)

这两段代码能够清晰的展现出,用promise封装后使用起来的方便.

然后 我们顺着这个思路一步步把这个弹窗写出来,首先这个构造函数中有一个show方法这个show方法,要做的事情就是让这个弹窗弹出来,并且他要接受一些参数来完成自定义弹窗,最重要的是它要返回一个promise对象,这样才能执行后面的then,catch。(这里粗略的补充一下,其实用好peomise记住一个口诀就可以了,resolve()调用执行then,reject()调用执行catch,虽然很粗暴但是很实用。)

class Madal {
  show(props) {
    return new Promise((resolve, reject) => {
    
      let dom = document.createElement("div");
      
      const JSXdom = (<MyModal {...props} resolve={resolve} reject={reject}></MyModal>)
      
      //下面的操作就是把这个弹窗添加到 body上面
      ReactDOM.createRoot(dom).render(JSXdom);
      
      document.body.appendChild(dom);
    });
  }
}

上面的myModal是我对antd中Modal的二次封装,我们把resolve 和reject这两个函数传下去,在点击取消和确定时执行一下就可以了

export default function MyModal(props) {

  const [visible, setVisible] = useState(true);
  //弹窗默认参数
  const {
    title = "删除",
    content = "你确定要删除么",
    okText = "确认",
    canCelText = "取消",
    reject,
    resolve,
  } = { ...props };
  
  useEffect(() => {
    setVisible(true);
  }, []);
  
  const handleOk = () => {
    resolve("点击确认");
    setVisible(false);
  };
  
  const canCel = () => {
    reject("点击取消");
    setVisible(false);
  };
  return (
    <div className="dvv">
      <Modal
        title={title}
        visible={visible}
        cancelText={canCelText}
        okText={okText}
        onOk={handleOk}
        onCancel={canCel}
      >
        {content}
      </Modal>
    </div>
  )
}

最后我们来调用一下看看效果

let m = new Madel();
    m.show({ title: "我的弹窗", content: "今晚打老虎" })
      .then((res) => {
        console.log(res, "========确认");
      })
      .catch((res) => {
        console.log(res, "==========取消");
      });

madel.gif

Effect完成一段动画

ainamatel.gif

import React, { useRef, useState, useEffect } from "react";
import anime from "animejs";

export default function Index() {

  const element = useRef(null);
  const status = useRef(true);
  const [animaGo, setAnimaGo] = useState(false);
  const [animaTo, setAnimaTo] = useState(false);
  
  useEffect(() => {
    animaGo && goMove();
    animaTo && ToMove();
  }, [animaGo, animaTo]);
  
  //向左运动
  function goMove() {
    anime({
      targets: element.current,
      translateX: 500,
      backgroundColor: "#66FF00",
      borderRadius: ["0%", "50%"],
      complete: () => {
        setAnimaGo(false);
        setAnimaTo(true);
      },
    });
  }
  
  //向右边运动
  function ToMove() {
    anime({
      targets: element.current,
      translateX: 0,
      backgroundColor: "#FFF",
      borderRadius: ["50%", "0%"],
      easing: "easeInOutQuad",
      complete: () => {
        setAnimaTo(false);
        status.current = true;
      },
    });
  }
  
  function handleStatus() {
    if (status.current) {
      status.current = false;
      setAnimaGo(true);
    }
  }
  
  return (
    <div>
      <div className="box" onClick={handleStatus}>
        <div ref={element} className="childBox"></div>
        {animaGo && "第一段动画执行"}
        {animaTo && "第二段动画执行"}
      </div>
    </div>
  );
}

这一小段动画很简单,但是它却体现了我们如何更好的去使用Effect函数,这里就是用开关思维让effect去控制事件在合适的时机去执行

vue3+pinia一个小购物车

cart.gif

这个demo主要就是想感受一下pina,结果就是不要太方便,相比vuex4它最大的亮点我觉得是

去掉了mutations,它状态的改变,变得非常简单只能通过actions 这无疑让我们的状态管理变得非常单一和清晰。

@/store/Cart

import { defineStore } from "pinia";
interface List {
  goods: string;
  price: number;
  num: number;
  myNum: number;
  id: string;
}
const useCart = defineStore("Cart", {
  state: () => ({
    pricelist: [
      {
        goods: "金瓶梅",
        price: 10,
        num: 10,
        myNum: 0,
        id: "jpm",
      },
      {
        goods: "西厢记",
        price: 20,
        num: 10,
        myNum: 0,
        id: "xxj",
      },
      {
        goods: "牡丹亭",
        price: 30,
        num: 10,
        myNum: 0,
        id: "mdt",
      },
    ],
  }),
  getters: {
    tatolMoney: (state: any) => {
      return state.pricelist.reduce(
        (sum: number, item: List) => sum + item.price * item.myNum,
        0
      );
    },
  },
  actions: {
    add(id: string) {
      this.pricelist.map((el) => {
        if (el.id == id) {
          el.myNum++;
          el.num--;
        }
      });
    },
    //结算
    sub(id: string) {
      this.pricelist.map((el) => {
        if (el.id == id) {
          el.myNum--;
          el.num++;
        }
      });
    },
  },
});
export default useCart;

无论多复杂的页面,只需要,state,getters,actions这三个api就够了,而且,在getters,actions中都可以直接 通过this去访问到state。接下来看一下在组件中的使用

List组件

<template>
  <el-row class="col" v-for="el in listData" :key="el.id">
    <div class="box">
      <span> <b>名称:</b>{{ el.goods }} </span>
      <span> <b>价格:</b>{{ el.price }} </span>
      <span> <b>剩余数量:</b>{{ el.num }} </span>
    </div>
    <div class="buy">
      <el-button :disabled="el.num == 0" @click="store.add(el.id)">+</el-button>
      {{ el.myNum }}
      <el-button :disabled="el.myNum == 0" @click="store.sub(el.id)">-</el-button>
    </div>
  </el-row>
</template>

<script setup lang="ts">

import useCart from "@/store/Cart";
const store = useCart();
const listData = store.pricelist;

</script>

状态的引用再也不会用到令人费解的...map映射在计算属性中。仓库里的所有东西都可以通过store去访问到,它的add,和sub方法也是一样的.

<template>
  <div><el-button type="primary">总价</el-button>¥{{ tatolMoney }}</div>
</template>

<script lang="ts" setup>
import useCart from "@/store/Cart";
import { storeToRefs } from "pinia";
//import { computed } from "vue";

const store = useCart();
const { tatolMoney } = storeToRefs(store);
//const tatolMoney = computed(() => store.tatolMoney);

</script>
<style lang="sxss" spoted></style>

这里是它计算属性的使用,可以直接通过store在模板中访问到,如果想在模板中看起来简洁一点可以用计算属性,也可以用pinia提供的storeToRefs去解构,它还可以解构action中的方法state中的状态。是引用变得简洁