vue3项目总结

236 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第6天,点击查看活动详情image.png

前言

公司最近新开始了一个项目,因为一开始就我自己写,所以技术调研也就看我想用什么了,在react和vue3之中选择,因为之前是使用react的,最近vue3话题相当火热,作为一个不甘落后的搬砖er,当然是要用一下新小推车,感受一下其它工具。写了一段时间之后,对于使用的vue3相关内容进行一个记录。

image.png

套内工具

setup语法糖

<script setup>
</script>

只能说用了setup语法之后写代码就变的顺手了起来,如果单个组件写了较多的代码时没有割裂感,script区域内容不再需要return才能在template中使用。

setup组件中的生命周期钩子
从下图可以明显看出,setup与传统写法少了beforeCreate和created两个钩子。因为如果你想要在这两个钩子中执行的内容完全可以直接卸载setup中,也就不需要这两个钩子函数了。而且所有的生命周期钩子都是传入一个回调方法来执行,不再使用函数写法。

image.png

setup组件的基本用法

<template>
<div class="people">
    <h2>姓名:{{name}}</h2>
    <h3>年龄:{{age}}</h3>
    <div v-for="(item,index) in hobby" :key="index">
        <h3>'爱好'{{index + 1}} +':'{{item}}</h3>
    </div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue';
const name = ref('小李');
const age = ref(20);
const hobby = reactive<string[]>(['football','swimming']);
</script>

setup 组件和普通的composition组件有一些api的用法不同,例如props和emits改为defineProps和defineEmits,但是这两个Api不需要引入,直接就可以使用。

const props = defineProps({
    name: string,
    age: number
});
// 使用时 props.name
const parentEmitFunc = defineEmits(['addUser','deleteUser']);
// 使用时 
parentEmitFunc('addUser', '小王','15');

在vue中watch和computed无疑是最为重要的api,他们最能体现vue响应式更新的特点,vue3中除此之外还新增了一个与react hooks类似的功能 watchEffect 它会立即执行传入的函数,并且每当函数中任意一个响应式数据更新时都会立即重新运行该函数。

const count = ref(0)
watchEffect(() => console.log(count.value))

同时watch也进行了升级,在具备既有功能的同时,增加了侦听多个源的功能,watch和watchEffect大家可以根据自己的需求来进行使用

watch(count, (count, prevCount) => {
  /* ... */
})

watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => {
  /* ... */
})

如果你想要在父组件使用自组件的数据和方法使用defineExpose

// 父组件
<template>
parent
<Son ref="son"/>
<button @click="outputData">button</button>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue';
import Son from './Son.vue';
const son = ref<InstanceType<typeof Son>>();

const outputData = ():void => {
    console.log(son.value.data);
}
</script>
// 子组件
const data = {}
defineExpose({
  data
})

状态驱动的动态 CSS

因为我们新的项目拥有两个主题色,所以在查看了官方文档的css modules和动态css两个功能介绍后,自己想要对主题实现更为灵活,选择了动态css。这两种方式都很不错,主要是看你想使用哪种。 在这里直接搬过来一部分代码,大家可以参考一下我写的思路。

// ** theme.js
import {reactive} from 'vue';

export const blackStyle = {
    mainBackgroundColor:  '#0A0D14',
    containerBackgroundColor: '#15182B',
    containerBoxShadow: '0px 1px 8px 2px rgba(19, 22, 35, 0.5)',
    sceneCreateCardBackground: '#262D49',
    sceneCreateCardFontColor: '#C7D5E4',
}

export const whiteStyle = {
    mainBackgroundColor:  '#fff',
    containerBackgroundColor: '#FCFEFF',
    containerBoxShadow: '0px 1px 8px 2px rgba(183, 187, 194, 0.5)',
    sceneCreateCardBackground: '#D6DDE4',
    sceneCreateCardFontColor: '#8fa4bb',
}

export const themeStyle = reactive({
    style: null
})

// ** header.vue
<script setup >
import { themeStyle, whiteStyle, blackStyle } from "@/assets/theme";
// 主题切换
const themeActive = () => {
  let localTheme = store.state.theme || localStorage.getItem("theme");
  if (localTheme === "black") {
    localTheme = "white";
  } else {
    localTheme = "black";
  }
  setSceneStyle(localTheme);
};
// 更改style
const setSceneStyle = (localTheme) => {
  let theme = localTheme || store.state.theme || localStorage.getItem("theme");
  store.commit("CHANGE_THEME", theme);
  themeStyle.style = theme == "black" ? blackStyle : whiteStyle;
  localStorage.setItem("theme", theme);
};
</script>
<style>
  background: v-bind("themeStyle.style.header.backgroundColor");
  box-shadow: v-bind("themeStyle.style.header.borderShadow");
</style>

套外工具

vite 官网地址

image.png
优点:

  • 热更新非常快
  • vue官方推荐,对vue单文件组件完全支持 缺点:
  • 生态暂时还不太好,不如webpack
  • 不能使用commonjs语法,例如require export是不能用的

这个我也只是走了一下流程,大家可以去官网查看一下,讲得比较详细,只是有一个问题需要给大家提示一下

如果使用vite+vue-router,你在路由页面中出现的组件要小驼峰命名,不然vite不能热更新,正确示例:

image.png

ElementPlus

image.png
优点:

  • ElementUI维护团队对Vue3进行的一次升级
  • table组件自带有虚拟滚动 缺点:
  • 按需引入比较麻烦

按需引入使用

有个需要特别注意的是,弹出框的样式需要在main.js中单独引用,如果在组件script中需要使用的话,再从插件中按需导出

// vite.config.js
import AutoImport from 'unplugin-auto-import/vite';
import Components from 'unplugin-vue-components/vite';
import ElementPlus from 'unplugin-element-plus/vite';
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';

plugins: [
    vue(),
    ElementPlus(),
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver()],
    }),
  ],
  
// main.js

import 'element-plus/es/components/message-box/style/css'
import 'element-plus/es/components/message/style/css'
// use.vue
import {
    ElMessageBox,
    ElMessage,
} from "element-plus";
ElMessageBox.confirm(msg, "提示", {
    confirmButtonText: "确定",
    cancelButtonText: "取消",
    type: "warning",
})
    .then(() => {
        callback();
    })
    .catch(() => {

    });

pinia 官网

image.png

介绍

vue的状态管理工具,它是跟随vue3一同发布,也是核心成员开发的。尤大也推荐大家去使用它,它只有1kb的大小,比vuex轻量化,更加适合小型项目。pinia去除了同步方法、异步方法的区分,对于ts的支持性更好。

应用

安装:
npm install pinia@next
yarn add pinia@next 使用

// store/counter.js
import { defineStore } from "pinia";

export const useStore = defineStore('index',{
  state: ()=> ({
    count: 1
  }),
  // 和vuex getters相同
  getters: {
      getCount(state) {
          return state.count;
      }
  },
  // 同步 异步 都写在这里
  actions: {
      addCount(num){
          this.count += num;
      }
  }
});

// index.vue

import { useCounterStore } from  '@/stores/counter';
counter.addCount(3)

继续学习 GO