使用vite工具搭建项目
使用技术:vite+vue3+typescript
项目地址:https://github.com/shenshuai89/vite-vue3-ts

项目搭建

官方推荐两种方式安装

  • vite

npm init vite-app vite-vue3-ts # OR yarn create vite-app vite-vue3-ts

  • cli

    1. npm install -g @vue/cli # OR yarn global add @vue/cli<br />vue create vite-vue3-ts<br />`vite` 是一个由原生`ESM`驱动的Web开发构建工具,打开 `vite` 依赖的 `package.json` 可以发现在 `devDependencies` 开发依赖里面已经引入了`TypeScript` ,甚至还有 `vuex` , `vue-router` ,`less` , `sass` 这些本地开发经常需要用到的工具。`vite` 轻量,开箱即用的特点,满足了大部分开发场景的需求,作为快速启动本地 `Vue` 项目来说,这是一个非常完美的工具。

    安装依赖

    yarn

    使用yarn启动项目

    yarn dev

    引入typescript

    安装

    1. yarn add typescript -D

    初始化tsconfig.json

    1. npx tsc --init

    main.js修改为main.ts,同时将index.html里面的引用也修改为main.ts,
    然后在script 里添加 lang=”ts”

    由于ts无法识别vue文件,还需要配置一个文件

    在项目根目录添加shim.d.ts文件

    1. declare module "*.vue" {
    2. import { Component } from "vue";
    3. const component: Component;
    4. export default component;
    5. }

    Composition API风格

    compositionAPI目的是把功能相同的代码放在一起维护。维护一个功能点时,只用修改当前的功能逻辑。compositionAPI通过setup选项组织代码。

    1. export default {
    2. setup(props, context) {}
    3. };

    新语法的范式:

    1. export default {
    2. setup() {
    3. const { networkState } = useNetworkState();
    4. const { user } = userDeatil();
    5. const { list } = tableData();
    6. return {
    7. networkState,
    8. user,
    9. list,
    10. };
    11. },
    12. };
    13. function useNetworkState() {}
    14. function userDeatil() {}
    15. function tableData() {}

vue3Composition API 代码风格中,比较有代表性的api就是 refreactive

ref和computed

  • ref将基本类型转为响应式数据,取数据时获取value
  • computed计算属性数据,缓存的数据

    1. import { computed, ref } from "vue";
    2. export default {
    3. setup() {
    4. const msg = ref("北鸟南游");
    5. const age = ref(5);
    6. // computed 计算属性的使用
    7. const double = computed(() => {
    8. return age.value * 2;
    9. });
    10. const add = () => {
    11. age.value += 1;
    12. };
    13. return { msg, age, add, double };
    14. },
    15. };

    reactive和toRefs

  • reactive将对象转为响应式数据

  • toRefs将响应式对象变成普通对象

    1. import { computed, reactive, ref, toRefs } from "vue";
    2. interface Person {
    3. name: string;
    4. age: number;
    5. }
    6. export default {
    7. setup() {
    8. // 使用reactive将对象转为响应式数据
    9. const state: Person = reactive({
    10. name: "北鸟南游",
    11. age: 5,
    12. double: computed(() => {
    13. return state.age * 2;
    14. }),
    15. });
    16. const add = () => {
    17. state.age += 1;
    18. };
    19. //toRefs将响应式对象变成普通对象
    20. return { ...toRefs(state), add };
    21. },
    22. };

    props和context父子组件 属性传递

    props是父组件传入的数据,context是一个上下文对象,是从2.x暴露出来的一些属性:attrs、slots、emit。
    注:props的数据也需要通过toRefs解构,否则响应式数据会失效。
    代码文件

  • views/person3.vue

  • views/person4.vue
  • components/PersonInfo.vue
    1. <!-- 父组件 -->
    2. <template>
    3. <div id="person">
    4. <PersonInfo :info="msg"></PersonInfo>
    5. <div>{{ name }}年龄为{{ age }}</div>
    6. <button @click="add">+</button>
    7. <div>年龄的2倍{{ double }}</div>
    8. </div>
    9. </template>
    10. <script lang="ts">
    11. import { computed, reactive, ref, toRefs } from "vue";
    12. import PersonInfo from "../components/PersonInfo.vue";
    13. interface Person {
    14. name: string;
    15. age: number;
    16. }
    17. export default {
    18. components: {
    19. PersonInfo,
    20. },
    21. setup() {
    22. // 使用reactive将对象转为响应式数据
    23. const state: Person = reactive({
    24. name: "北鸟南游",
    25. age: 5,
    26. msg: "vue3前端开发",
    27. double: computed(() => {
    28. return state.age * 2;
    29. }),
    30. });
    31. const add = () => {
    32. state.age += 1;
    33. };
    34. //toRefs将响应式对象变成普通对象
    35. return { ...toRefs(state), add };
    36. },
    37. };
    38. </script>
    1. <!-- 子组件 -->
    2. <template>
    3. <div>描述:{{ data }}</div>
    4. <button @click="emitName">开心学习!</button>
    5. </template>
    6. <script>
    7. import { ref } from "vue";
    8. export default {
    9. props: {
    10. info: String,
    11. },
    12. setup(props, context) {
    13. //利用 setup 的第一个参数获取 props 使用
    14. // console.log(props);
    15. const data = ref(props.info);
    16. // 子组件向父组件发送事件
    17. const emitName = () => {
    18. context.emit("learn", "学习vue3");
    19. };
    20. return { data, emitName };
    21. },
    22. };
    23. </script>

    watch和watchEffect监听

    watch数据变化,和vue2中的watch类似

    watch默认情况是懒执行的,也就是说仅在侦听的源变更时才执行回调,不能立即执行。
    watch监听state的age数据变化。
    1. // 第一个参数:监听的数据源
    2. // 第二个是回调函数,当监听的数据发生变化,执行回调函数,并且可以获取到新值和旧值。
    3. watch(
    4. () => state.age,
    5. (newVal, oldVal, clean) => {
    6. console.log(
    7. state.name + "去年:" + oldVal + "岁,今年:" + newVal + "岁。"
    8. );
    9. // clean处理重复性的watch监听事件
    10. clean(() => {
    11. console.log("clean");
    12. });
    13. }
    14. );
    watch监听ref
  1. 不指定数据源

    1. // watchEffect不指定数据源,会监听回调函数中所有的值的改变就会执行。
    2. const age = ref(18)
    3. watchEffect(()=>{
    4. console.log(age.value)
    5. })
  2. 指定数据源

    1. const age = ref(18)
    2. // watch监听的数据源,如果是ref定义的数据,可以直接设置为第一个参数。如果是reactive定义的数据,需要传回调函数
    3. watch(age,()=> {
    4. // ref对象监听的是对象的value
    5. console.log(age.value)
    6. })
    7. //使用reactive定义age
    8. const data = reactive({
    9. age: 5
    10. })
    11. watch(()=>data.age, (newVal, oldVal)=> {
    12. // ref对象监听的是对象的value
    13. console.log(newVal, oldVal)
    14. })

watch监听reactive

  1. const state: Person = reactive({
  2. name: "北鸟南游",
  3. age: 5,
  4. msg: "vue3前端开发",
  5. double: computed(() => {
  6. return state.age * 2;
  7. }),
  8. });
  1. 不指定数据源

    1. watchEffect(()=>{
    2. console.log(state.age)
    3. })
  2. 指定数据源

    1. watch(()=>state.age,()=>{
    2. console.log(state.age)
    3. })

    3.监听多个数据源,数组中参数任意一个变化,都会监听到值变化。

    1. watch(
    2. [() => state.age, () => state.name],
    3. ([newName, newAge], [oldName, oldAge]) => {
    4. console.log(newName);
    5. console.log(newAge);
    6. console.log(oldName);
    7. console.log(oldAge);
    8. }
    9. )

    watchEffect的使用

    watchEffect立即执行回调函数,不用指定数据源,响应式追踪其依赖,并在其依赖变更时重新运行该函数。
    watchEffect自动收集回调函数中包含的参数值的变化,并进行监听。 ```typescript

  1. <a name="u9dwJ"></a>
  2. #### watchEffect与watch的区别:
  3. 1、watch 是需要传入侦听的数据源,而 watchEffect 是**自动收集数据源作为依赖**。<br />2、watch 可以访问侦听状态变化前后的值,而 watchEffect 只能获取到变化后的值,无法获取oldValue。<br />3、watch 是属性改变的时候执行,而 watchEffect 是默认会立即执行一次,然后属性改变也会执行。
  4. <a name="vCjYp"></a>
  5. ### provide、inject依赖注入数据
  6. 代码参考文件
  7. - components/Son.vue
  8. - components/Grandson.vue
  9. - App.vue
  10. App.vue
  11. ```javascript
  12. import Son from "./components/Son.vue"
  13. export default {
  14. setup() {
  15. provide('themecolor', 'orange')
  16. }
  17. };

Son.vue

  1. <template>
  2. <div>
  3. <h3 :style="{ color: color }">son 组件</h3>
  4. <Grandson></Grandson>
  5. </div>
  6. </template>
  7. <script lang="ts">
  8. import { inject } from "vue";
  9. import Grandson from "./Grandson.vue";
  10. export default {
  11. components: {
  12. Grandson: Grandson,
  13. },
  14. setup() {
  15. const color = inject("themecolor");
  16. return {
  17. color,
  18. };
  19. },
  20. };
  21. </script>

Grandson.vue

  1. <template>
  2. <div>
  3. <h5 :style="{ color: color }">grandson 组件</h5>
  4. </div>
  5. </template>
  6. <script lang="ts">
  7. import { inject } from "vue";
  8. export default {
  9. name: "grandson",
  10. setup() {
  11. const color = inject("themecolor");
  12. return {
  13. color,
  14. };
  15. },
  16. };
  17. </script>

provide和inject的使用对有层级关系的组件,可以跨组件进行数据传递

生命周期LifeCycle Hooks

新版的生命周期函数,可以按需导入到组件中,且只能在 setup() 函数中使用, 但是也可以在setup 外定义, 在 setup 中使用

  1. <script lang="ts">
  2. import { defineComponent, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onErrorCaptured, onMounted, onUnmounted, onUpdated } from 'vue';
  3. export default defineComponent({
  4. setup(props, context) {
  5. onBeforeMount(()=> {
  6. console.log('beformounted!')
  7. })
  8. onMounted(() => {
  9. console.log('mounted!')
  10. })
  11. onBeforeUpdate(()=> {
  12. console.log('beforupdated!')
  13. })
  14. onUpdated(() => {
  15. console.log('updated!')
  16. })
  17. onBeforeUnmount(()=> {
  18. console.log('beforunmounted!')
  19. })
  20. onUnmounted(() => {
  21. console.log('unmounted!')
  22. })
  23. onErrorCaptured(()=> {
  24. console.log('errorCaptured!')
  25. })
  26. return {}
  27. }
  28. });
  29. </script>

fragment组件

在vue2中,组件模版必须有根节点

  1. <template>
  2. <div>
  3. <span></span>
  4. <span></span>
  5. </div>
  6. </template>

在Vue3中我们可以直接不需要根节点:

  1. <template>
  2. <span>hello</span>
  3. <span>world</span>
  4. </template>

teleport组件

可以将插槽中的元素或者组件传送到页面指定的其他位置。Teleport一个常见的使用场景,在一些嵌套比较深的组件来转移模态框的位置。虽然在逻辑上模态框是属于该组件的,但是在样式和DOM结构上,嵌套层级后较深后不利于进行维护(z-index等问题)

  1. <template>
  2. <button @click="showDialog = true">打开模态框</button>
  3. <teleport to="body">
  4. <div class="modal" v-if="showDialog" style="position: fixed">
  5. 我是一个模态框
  6. <button @click="showDialog = false">关闭</button>
  7. <child-component :msg="msg"></child-component>
  8. </div>
  9. </teleport>
  10. </template>
  11. <script>
  12. export default {
  13. data() {
  14. return {
  15. showDialog: false,
  16. msg: "hello"
  17. };
  18. },
  19. };
  20. </script>

以上代码的teleport中的modal被传送到body标签底部。
虽然在不同的地方进行渲染,但是Teleport中的元素和组件还是属于父组件的逻辑子组件,还是可以和父组件进行数据通信。
teleport接收两个参数:to【string类型】和disabled【boolean类型】

  • to:必须是有效的查询选择器或 HTMLElement,可以id或者class选择器等
  • disabled:如果是true表示禁用teleport的功能,其插槽内容将不会移动到任何位置,默认false不禁用

Suspense组件

Vue3 新增 React.lazy 类似功能的 defineAsyncComponent 函数,处理动态引入(的组件)。defineAsyncComponent可以接受返回承诺的工厂函数。当您从服务器检索到组件定义时,应该调用Promise的解析回调。您还可以调用reject(reason)来指示加载已经失败
动态加载组件

  1. import { defineAsyncComponent } from 'vue'
  2. const AsyncComp = defineAsyncComponent(() =>
  3. import('./components/AsyncComponent.vue')
  4. )
  5. app.component('async-component', AsyncComp)

suspense的应用

  1. <template>
  2. <Suspense>
  3. <template #default>
  4. <my-component />
  5. </template>
  6. <template #fallback>
  7. Loading ...
  8. </template>
  9. </Suspense>
  10. </template>
  11. <script lang='ts'>
  12. import { defineComponent, defineAsyncComponent } from "vue";
  13. const MyComponent = defineAsyncComponent(() => import('./Component'));
  14. export default defineComponent({
  15. components: {
  16. MyComponent
  17. },
  18. setup() {
  19. return {}
  20. }
  21. })
  22. </script>

非兼容的功能v2和v3区别

data、mixin、filter(v3已经删除)

在vue2中data可以定义object或function,如果定义成object,则数据会相互影响,因为object是引用类型。
在vue3中data只接受function,通过function返回对象;
mixin使用发生了改变,当mixin和data合并时,会执行浅拷贝合并。

  1. const Mixin = {
  2. data() {
  3. return {
  4. user: {
  5. name: 'Jack',
  6. id: 1,
  7. address: {
  8. prov: 2,
  9. city: 3,
  10. },
  11. }
  12. }
  13. }
  14. }
  15. const Component = {
  16. mixins: [Mixin],
  17. data() {
  18. return {
  19. user: {
  20. id: 2,
  21. address: {
  22. prov: 4,
  23. },
  24. }
  25. }
  26. }
  27. }
  28. // vue2结果:
  29. {
  30. id: 2,
  31. name: 'Jack',
  32. address: {
  33. prov: 4,
  34. city: 3
  35. }
  36. }
  37. // vue3结果:
  38. user: {
  39. id: 2,
  40. address: {
  41. prov: 4,
  42. },
  43. }

vue2.x会进行深拷贝,对data中的数据向下深入合并拷贝;而vue3只进行浅层拷贝,对data中数据发现已存在就不合并拷贝。

v-model

在vue2中v-model相当于绑定value属性和input事件,本质是一个语法糖;

  1. <child-component v-model="msg"></child-component>
  2. <!-- 相当于 -->
  3. <child-component :value="msg" @input="msg=$event"></child-component>

但是在特殊情况下,需要对多值进行双向绑定,其他值的显示就需要使用回调函数来改变。

  1. <child-component
  2. v-model="msg"
  3. :msg1="msg1"
  4. @change1="msg1=$event"
  5. :msg2="msg2"
  6. @change2="msg2=$event">
  7. </child-component>

在vue2.3+以后新增.sync修饰符,本质也是语法糖,是在组件上绑定@update:propName回调,语法更简洁。

  1. <child-component
  2. :msg1.sync="msg1"
  3. :msg2.sync="msg2">
  4. </child-component>
  5. <!-- 相当于 -->
  6. <child-component
  7. :msg1="msg1"
  8. @update:msg1="msg1=$event"
  9. :msg2="msg2"
  10. @update:msg2="msg2=$event">
  11. </child-component>

vue3将v-model和.sync修饰符进行整合,弃用sync属性,使用多个value绑定值直接用多个v-model。单个v-model将v-model默认传的prop名称由value改成modelValue:

单个v-model

  1. <child-component
  2. v-model="msg">
  3. </child-component>
  4. <!-- 相当于 -->
  5. <child-component
  6. :modelValue="msg"
  7. @update:modelValue="msg = $event">
  8. </child-component>

多个v-model

v-model传递多个值,可以将一个argument传递给v-model

  1. <child-component
  2. v-model.msg1="msg1"
  3. v-model.msg2="msg2">
  4. </child-component>
  5. <!-- 相当于 -->
  6. <child-component
  7. :msg1="msg1"
  8. @update:msg1="msg1=$event"
  9. :msg2="msg2"
  10. @update:msg2="msg2=$event">
  11. </child-component>

v-for和key

在vue2中,v-for不能绑定在template上,v-for每次循环都需要给每个子节点一个唯一的key

  1. <template v-for="item in list">
  2. <div :key="item.id">...</div>
  3. <span :key="item.id">...</span>
  4. </template>

vue3中key值可以被放到template标签,就不能为每个子节点设置key

  1. <template v-for="item in list" :key="item.id">
  2. <div>...</div>
  3. <span>...</span>
  4. </template>

v-bind

在vue2中,v-bind绑定一个对象时,对象中的值会被属性值覆盖

  1. <div id="red" v-bind="{ id: 'blue' }"></div>
  2. <div v-bind="{ id: 'blue' }" id="red"></div>
  3. <!-- 最后结果都相同 -->
  4. <div id="red"></div>

vue3中,如果v-bind绑定的对象里包含属性值,同时又定义属性值,那么会使用后定义的值为准。

  1. <!-- template -->
  2. <div id="red" v-bind="{ id: 'blue' }"></div>
  3. <!-- result -->
  4. <div id="blue"></div>
  5. <!-- template -->
  6. <div v-bind="{ id: 'blue' }" id="red"></div>
  7. <!-- result -->
  8. <div id="red"></div>

v-for中的ref属性

vue2中在v-for中使用ref属性,通过this.$refs会得到一个数组

  1. <template
  2. <div v-for="item in list" :ref="setItemRef"></div>
  3. </template>
  4. <script>
  5. export default {
  6. data(){
  7. list: [1, 2]
  8. },
  9. mounted () {
  10. // [div, div]
  11. console.log(this.$refs.setItemRef)
  12. }
  13. }
  14. </script>

这样的数组可能不是想要的结果,因此vue3不再自动创建数组,而是将ref变为函数,该函数默认传入该节点

  1. <template
  2. <div v-for="item in 3" :ref="setItemRef"></div>
  3. </template>
  4. <script>
  5. import { reactive, onUpdated } from 'vue'
  6. export default {
  7. setup() {
  8. let itemRefs = reactive([])
  9. const setItemRef = el => {
  10. itemRefs.push(el)
  11. }
  12. onUpdated(() => {
  13. console.log(itemRefs)
  14. })
  15. return {
  16. itemRefs,
  17. setItemRef
  18. }
  19. }
  20. }
  21. </script>

v-if和v-for的优先级

vue2中,v-for和v-if同时使用v-for有更高的优先级,因此vue2做性能优化的一点就是不能把v-for和v-if放在同一个元素上。
vue3中,v-if比v-for有更高优先级。下面代码在vue2中可以允许,但是在vue3中,没有item变量时会报错

  1. <template>
  2. <div v-for="item in list" v-if="item % 2 === 0" :key="item">{{ item }}</div>
  3. </template>
  4. <script>
  5. export default {
  6. data() {
  7. return {
  8. list: [1, 2, 3, 4, 5],
  9. };
  10. },
  11. };
  12. </script>

自定义hooks

解决vue2中mixin数据来源不清晰的问题,hook可以完成逻辑的复用
创建hooks文件夹,用来存放可复用的组件
创建useCount.ts文件

  1. import { ref, Ref, watch } from "vue";
  2. interface Range {
  3. min?: number;
  4. max?: number;
  5. }
  6. interface Result {
  7. current: Ref<number>;
  8. inc: (delta?: number) => void;
  9. dec: (delta?: number) => void;
  10. set: (value: number) => void;
  11. reset: () => void;
  12. }
  13. export default function useCount(initialVal: number, range?: Range): Result {
  14. const current = ref(initialVal);
  15. const inc = (delta?: number): void => {
  16. if (typeof delta === "number") {
  17. current.value += delta;
  18. } else {
  19. current.value += 1;
  20. }
  21. };
  22. const dec = (delta?: number): void => {
  23. if (typeof delta === "number") {
  24. current.value -= delta;
  25. } else {
  26. current.value -= 1;
  27. }
  28. };
  29. const set = (value: number): void => {
  30. current.value = value;
  31. };
  32. const reset = () => {
  33. current.value = initialVal;
  34. };
  35. watch(current, (newVal: number, oldVal: number) => {
  36. console.log(newVal);
  37. if (newVal === oldVal) return;
  38. if (range && range.min && newVal < range.min) {
  39. current.value = range.min;
  40. } else if (range && range.max && newVal > range.max) {
  41. current.value = range.max;
  42. }
  43. });
  44. return {
  45. current,
  46. inc,
  47. dec,
  48. set,
  49. reset,
  50. };
  51. }

在Count.vue中引用

  1. import useCount from "../hooks/useCount";
  2. export default {
  3. setup() {
  4. const { current: count, inc, dec, set, reset } = useCount(2, {
  5. min: 1,
  6. max: 15,
  7. });
  8. const msg = ref("Demo useCount");
  9. return {
  10. count,
  11. inc,
  12. dec,
  13. set,
  14. reset,
  15. msg,
  16. };
  17. },
  18. };

添加router

安装vue-router

  1. yarn add vue-router@latest

配置vue-router

在项目src目录下面新建router目录,然后添加index.ts文件

  1. import {createRouter, createWebHashHistory} from 'vue-router'
  2. // 在 Vue-router新版本中,需要使用createRouter来创建路由
  3. export default createRouter({
  4. // 指定路由的模式,此处使用的是hash模式
  5. history: createWebHashHistory(),
  6. // 路由地址
  7. routes: []
  8. })

vue3完整组件结构

完整的vue 3.x 完整组件模版结构包含了:组件名称、 props、components、setup(hooks、computed、watch、methods 等)

  1. <template>
  2. <div class="mine" ref="elmRefs">
  3. <span>{{name}}</span>
  4. <br>
  5. <span>{{count}}</span>
  6. <div>
  7. <button @click="handleClick">测试按钮</button>
  8. </div>
  9. <ul>
  10. <li v-for="item in list" :key="item.id">{{item.name}}</li>
  11. </ul>
  12. </div>
  13. </template>
  14. <script lang="ts">
  15. import { computed, defineComponent, getCurrentInstance, onMounted, PropType, reactive, ref, toRefs } from 'vue';
  16. interface IState {
  17. count: 0,
  18. name: string,
  19. list: Array<object>
  20. }
  21. export default defineComponent({
  22. name: 'demo',
  23. // 父组件传子组件参数
  24. props: {
  25. name: {
  26. type: String as PropType<null | ''>,
  27. default: 'vue3.x'
  28. },
  29. list: {
  30. type: Array as PropType<object[]>,
  31. default: () => []
  32. }
  33. },
  34. components: {
  35. /// TODO 组件注册
  36. },
  37. emits: ["emits-name"], // 为了提示作用
  38. setup (props, context) {
  39. console.log(props.name)
  40. console.log(props.list)
  41. const state = reactive<IState>({
  42. name: 'vue 3.0 组件',
  43. count: 0,
  44. list: [
  45. {
  46. name: 'vue',
  47. id: 1
  48. },
  49. {
  50. name: 'vuex',
  51. id: 2
  52. }
  53. ]
  54. })
  55. const a = computed(() => state.name)
  56. onMounted(() => {
  57. })
  58. function handleClick () {
  59. state.count ++
  60. // 调用父组件的方法
  61. context.emit('emits-name', state.count)
  62. }
  63. return {
  64. ...toRefs(state),
  65. handleClick
  66. }
  67. }
  68. });
  69. </script>

添加vuex

安装vuex

yarn add vuex@latest
在项目src目录下面新建store目录,并添加index.ts文件

  1. import { createStore } from "vuex";
  2. interface State {
  3. userName: string;
  4. taskList: any[];
  5. }
  6. export default createStore({
  7. state: {
  8. userName: "北鸟南游",
  9. taskList: [],
  10. },
  11. getters: {
  12. totalList(state: State) {
  13. return state.taskList.length;
  14. },
  15. completeList(state: State) {
  16. return state.taskList.filter((list) => {
  17. return list.isfinished == true;
  18. }).length;
  19. },
  20. },
  21. mutations: {
  22. createTask(state: State, newTask: string) {
  23. state.taskList.push(newTask);
  24. },
  25. deleteTask(state: State, index: number) {
  26. state.taskList.splice(index, 1);
  27. },
  28. updateStatus(state: State, payload: any) {
  29. const { index, status } = payload;
  30. state.taskList[index].isfinished = status;
  31. },
  32. },
  33. });

在main.ts中引入router和vuex

  1. import router from "./router/index";
  2. import vuex from "./store/index";
  3. createApp(App).use(router).use(vuex).mount("#app");

项目todolist

集成路由和vuex数据管理
使用了scss预处理器,安装sass,yarn add sass -D
app.vue

  1. <div id="nav">
  2. <router-link to="/">count</router-link> |
  3. <router-link to="/todolist">todolist</router-link>
  4. </div>
  5. <router-view />

router/index.ts

  1. import { createRouter, createWebHashHistory } from "vue-router";
  2. // 在 Vue-router新版本中,需要使用createRouter来创建路由
  3. export default createRouter({
  4. // 指定路由的模式,此处使用的是hash模式
  5. history: createWebHashHistory(),
  6. // 路由地址
  7. routes: [
  8. {
  9. path: "/",
  10. // 必须添加.vue后缀
  11. component: () => import("../views/Count.vue"),
  12. },
  13. {
  14. path: "/todolist",
  15. name: "todolist",
  16. component: () => import("../views/TodoList.vue"),
  17. },
  18. ],
  19. });

store/index.ts

  1. import { createStore } from "vuex";
  2. interface State {
  3. userName: string;
  4. taskList: any[];
  5. }
  6. export default createStore({
  7. state: {
  8. userName: "北鸟南游",
  9. taskList: [],
  10. },
  11. getters: {
  12. totalList(state: State) {
  13. return state.taskList.length;
  14. },
  15. completeList(state: State) {
  16. return state.taskList.filter((list) => {
  17. return list.isfinished == true;
  18. }).length;
  19. },
  20. },
  21. mutations: {
  22. createTask(state: State, newTask: string) {
  23. state.taskList.push(newTask);
  24. },
  25. deleteTask(state: State, index: number) {
  26. state.taskList.splice(index, 1);
  27. },
  28. updateStatus(state: State, payload: any) {
  29. const { index, status } = payload;
  30. state.taskList[index].isfinished = status;
  31. },
  32. },
  33. });

项目地址:https://github.com/shenshuai89/vite-vue3-ts