vue3+ ts +vite pinia相关总结

基础

在vue3中一般返回的数据是不响应的,如果需要响应式需要在定义时声明(ref/reactive );

这点和vue2的不同,在 Vue2 中,我们只需要把数据放入 data 函数即具备响应式,Vue2 会遍历 data 中的所有属性,使用 Object.defineProperty拦截把每个 property 全部转为 getter/setter,getter 用来收集依赖,setter 用来执行 notify,发布更新事件.

Vue3基于proxy拦截实现响应式的能力,解决了vue2所遗留下来的一些问题(对象新增,数组下标修改不响应),是真正的响应式.但还是存在一些弊端(也不能叫弊端,操作和vue2习惯不一样而已).

1、 原始值的响应式实现 必须将他包装为一个对象Ref,通过.value 的方式访问.或包装为reactive

2、 直接赋值和ES6解构都会失去响应式.

需要通过修改对象的属性的形式,实现修改数据. reactiveVal.arr=[1,2,3]   refVal.value.arr=[1,2,3]

解构使用toRefs()代替ES6解构.

Vite(webpack和vite 都是现代化打包工具)

对非常基础的使用来说,使用 Vite 开发和使用一个静态文件服务器并没有太大区别。然而,Vite 还通过原生 ESM 导入提供了许多主要用于打包场景的增强功能.

在一个 Vite 项目中,index.html 在项目最外层而不是在 public 文件夹内。这是有意而为之的:在开发期间 Vite 是一个服务器,而 index.html 是该 Vite 项目的入口文件.

vite 以当前工作目录作为根目录启动开发服务器。你也可以通过 vite serve some/sub/dir 来指定一个替代的根目录。

Vue3+ts:

为了让 TypeScript 正确地推导出组件选项内的类型,我们需要通过 defineComponent() 这个全局 API 来定义组件.

import { defineComponent } from 'vue'

export default defineComponent({

  props: {

    name: String,

    msg: { type: String, required: true }

  },

  data() {

    return {

      count: 1

    }

  },

  mounted() {

    this.name // 类型:string | undefined

    this.msg // 类型:string

    this.count // 类型:number

  }

})

在使用了 <script lang="ts"> 或 <script setup lang="ts"> 后,所有的模板内表达式都将享受到更严格的类型检查,<template> 在绑定表达式中也支持 TypeScript。

Setup(组合式api)

vue3多了一种名为组合式api(composables api)的写法,相对应的式传统选项式api(options api),组合式api简单来说就是使用setup方式编写组件.

setup是vue3中的一个全新的配置项,setup是所有CompositionAPI(组合API)的基础,组件中所用到的数据、方法等都需要在setup中进行配置.

①、vue3支持向下兼容,vue2中的data、methods配置项在vue3中都能够使用,但是尽量不要将vue3中的配置项和vue2.x配置项混用;

②、vue2.x配置(data、methods、computed等)中可以访问setup中的属性、方法但是在setup中不能访问vue2.x配置(data、methods、computed等);

③、如果vue2.x配置与vue3配置存在重名,则以setup优先;

④、setup不能是一个async函数,因为返回值不再是return的对象,而是promise,模板看不到return对象中的属性.(使用async需suspense包裹父组件)

5.setup 函数,它将接受两个参数:(props、context(包含attrs、slots、emit)

props 是响应式的,你不能使用 ES6 解构,因为它会消除 prop 的响应性。如果需要解构 prop,可以通过使用 setup 函数中的toRefs 

attrs: 包含组件外部传递过来,但没有在props配置中声明的属性, 相当于 this.$attrs。

父子组件通信过程中,父组件把数据传递过来,如果子组件没有用props进行接收,就会出现在attrs中,而vm中没有如果用props接收了,则会出现在vm上而attrs中没有.

  1. setup函数是去掉了的 beforeCreate 和 created 两个阶段,同样的新增了一个 setup的函数.执行 setup 时,组件实例尚未被创建(在 setup() 内部,this 不会是该活跃实例的引用,即不指向vue实例,Vue 为了避免我们错误的使用,直接将 setup函数中的this修改成了undefined)

<div ref="container"></div>

function useCount() {

let count = ref(10);  //ref 会根据初始化时的值推导其类型,ref类型在底层会自动转换成reactive类型reactive({value: 10}),template里使用会自动添加.value

const book = reactive({ title: 'Vue ' }) //reactive() 也会隐式地从它的参数中推导类型,template里使用时不会自动添加.value

    let double = computed(() => {

        return count.value * 2;

    });

    const handleConut = () => {

        count.value = count.value * 2;

    };

    return {

        count,

        double,

        handleConut,

    };

}

export default defineComponent({

    setup() {

        const { count, double, handleConut } = useCount();

    onMounted(async () => {

console.log(container.value) // dom.   

      let AppProjectList = await apiStore.LBAPI({

      url: "AppProject",

      method: "get",

      });

    });

        return {

            count,

            double,

            handleConut,

          container,

        }

    },

});

Ref  toRef toRefs reactive proxy

ref、toRef、toRefs这三项在js中操作的时候都需要跟上‘.value’,页面当中正常使用无需‘.value’.

ref接受一个内部值并返回一个响应式且可变的 ref 对象,也就是ref可以接受一个普通类型的值,也可接受一个对象

let count = ref(10);  //ref 会根据初始化时的值推导其类型,ref类型在底层会自动转换成reactive类型reactive({value: 10}),template里使用会自动添加.value

console.log(count.value)

reactive 用于为对象添加响应式状态,接收一个js对象作为参数

数组【[]】也是对象,但是对于数组来说,不能用【=】号赋值,这样会取消数据的响应式

const book = reactive({ title: 'Vue ' }) //reactive() 也会隐式地从它的参数中推导类型,template里使用时不会自动添加.value

console.log(book.title)

toRef:可以用来为源响应式对象上的某个 property 新创建一个 ref(响应式).一次仅能设置一个数据,接收两个参数,第一个参数是哪个对象,第二个参数是对象的哪个属性

toRefs: 可以为一组源响应式属性添加响应式,接收一个对象作为参数,它会遍历对象身上的所有属性,然后挨个调用toRef执行.

对于toRef/toRefs创建数据,数据改变UI视图不变,这是由于初始定义的数据是非响应式.(let state1 = {name: '张三'})

但是对于toRef/toRefs创建数据,如果原始数据是响应式的,则UI视图会变化(let state1 = reactive({name: '张三'}))

第一种

let state1 = ref({name: '张三'})

let state2 = toRef(state1.value, 'name')// 通过ref定义的值,需要通过.value获取,即state1.value

console.log(state2.value.name)

第二种

let state1 = reactive({name: '张三'})

let state2 = toRef(state1, 'name')  // <=> toRefs(state1)

console.log(state2.value.name)

proxy对象如何取值.

1.JSON.parse(JSON.stringify(PDConfig.value.menuList))  //最有效

2.var list = toRaw(PDConfig.value.menuList)  

Vite.config.ts

export default ({ mode }: ConfigEnv) => {

  const dirRoot = process.cwd()

  const env = loadEnv(mode, dirRoot)

  return defineConfig({

    base: '/',  //等价于 vue3 的 publicPath. 配置打包出来的chunk.js等资源公共前缀路径

    plugins: [

      vue(),

      ElementPlus(),

      plainText(/\.hbs$/),

    ],

    server: {

      host: '0.0.0.0',

      port: 8002

    },

    resolve: {

      alias: {

        '@': pathResolve('./src'),

        'vue-i18n': pathResolve('./node_modules/vue-i18n/dist/vue-i18n.cjs.js'),

      },

    },

    define: {

      // setting vue-i18-next

      // Suppress warning

      __INTLIFY_PROD_DEVTOOLS__: false,

      __DEV__: process.env.NODE_ENV !== 'production',

      __PROD__: process.env.NODE_ENV === 'production',

    },

    optimizeDeps: {//默认情况下,不在 node_modules 中的,链接的包不会被预构建。使用此选项可强制预构建链接的包

      include: [

        '@monaco-editor/loader',

        'accounting',

        'axios',

        'axios-mock-adapter',

        'crypto-js',

        'dayjs',

        'echarts',

        'echarts-wordcloud',

        'element-plus',

        'gsap',

        'html2canvas',

        'js-cookie',

        'lodash-es',

        'mockjs',

        'monaco-editor',

        'naive-ui',

        'number-precision',

        'particles.vue3',

        'shortid',

        'vue',

        'vue-echarts',

        'vue-i18n',

        'vue-router',

      ],

      exclude: [],

    },

    build: {

      sourcemap: false,

      outDir: 'dist',

      rollupOptions: {

        input: {

          main: resolve(__dirname, 'index.html'),

        }

      },

    },

    esbuild: {

    },

  })

}

Watch

总结:vue3 wacth后是一个小括号,在小括号中操作,如果要监听ref单个的值,监听的值逗号箭头函数,箭头函数里面有两个形参,new,old,可以在对象中直接打印,监听多个值,可以在监听值的地方使用数组,多个值以逗号分隔

watch(pRef.value.obj, (newVal, oldVal)=> {  //对象无需 ()=>处理

      console.log(newVal, oldVal)

    },{deep:true})

监听ractive复杂对象类型 :wacth小括号,监听的对象逗号箭头函数,箭头函数中有两个值,new,old,在箭头函数对象中可以直接打印,如果要开启深度监听,在箭头函数后面加逗号,逗号后面是对象,对象中开启deep:true

例如:watch(() =>pRef.value.width, (newVal, oldVal)=> {   //基本类型变量需()=>处理 否则报错

      console.log(newVal, oldVal)

    },{deep:true})

如果要监听对象某一个值,例如person,在wacth小括号里以箭头函数形式监听对象某一个值

例如:watch(() =>person.name, (newVal, oldVal)=> {

      console.log(newVal, oldVal)

    })

如果监听person对象里的多个值:wacth小括号中以数组形式书写,在数组中用箭头函数

例如:watch([() =>person.name, ()=> person.age], (newVal, oldVal)=> {

      console.log(newVal, oldVal)

})

监听多个参数执行不同的方法

不过以上只是一些简单的例子,对于vue2中,watch可以监听多个源,并且执行不同的函数

正在上传…重新上传取消

在vue3中同理也能实现相同的情景,通过多个watch来实现,但在vue2中,只能存在一个watch

watch(count, () => {

console.log("count改变了");

});

watch(

    () => book.name,

    () => {

        console.log("书名改变了");

    }

);

监听多个参数执行相同的方法

在vue2中可能存在需要执行同一事件的情况,解决方法通常是利用computed把他们存入一个对象中,监听这个对象的变化

正在上传…重新上传取消

对于vue3,可以免去computed的操作

watch([() => book.name, count], ([name, count], [preName, preCount]) => {

console.log("count或book.name改变了");

});

挂载全局变量

2种方式:

  1. 通过provide/inject

2.注册全局变量

const app = createApp(App)

app.config.globalProperties.$httpUrl = 'https://www.baidu.com'

使用

import { defineComponent, getCurrentInstance, onMounted } from "vue"

export default defineComponent({

onMounted(() => {

      // console.log(this)

      const { appContext : { config: { globalProperties } } } = getCurrentInstance()

      console.log(globalProperties.$httpUrl)

    })

})

进阶

Pinia(vuex5,更适合vue3)

(1)它没有mutation,他只有state,getters,action【同步、异步】,可以直接修改state数据.而使用Vuex的时候每次修改state的值都需要调用mutations里的修改函数,因为Vuex需要追踪数据的变化

(2)他默认也是存入内存中,如果需要使用本地存储,使用pinia-plugin-persist

(3)pinia没有modules配置,没一个独立的仓库都是definStore生成出来的

  (4) pinia调用action,不需要在使用dispatch函数,直接调用store方法即可.一旦 store 被实例化,你就可以直接在 store 上访问 state、getters 和 actions 中定义的任何属性. 也支持vuex那样mapStores()、mapState() 或 mapActions()获取state的各种属性

import { defineStore } from "pinia";

export const storeA = defineStore("storeA", {

  state: () => {

    return {

      piniaMsg: "hello pinia",

      name: "xiao yue",

    };

  },

 getters: { // 与计算属性一样,可以组合多个getter。通过this访问任何其他 getter. 有缓存

    nameGetter(state) {// 自动将返回类型推断为字符串

      return state.name;    

},

  },

  actions: {

    setName(data) {

      this.name = data;  //直接修改state.  

    },

  },

});

组件App.vue中调用不需要再使用dispatch函数,直接调用store的方法即可

import { storeA } from '@/piniaStore/storeA'

export default {

  setup() {

let piniaStoreA = storeA()

piniaStoreA.setName('daming')  //action方法修改state <=> piniaStoreA.$patch({name:'daming'})

console.log(piniaStoreA.name)  //state变量   

console.log(piniaStoreA.nameGetter) // getter变量也是直接获取, 无需getter.xxx

let { piniaMsg, name } = storeToRefs(piniaStoreA)  //state解构

}

}

也支持vuex那样mapStores()、mapState() 或 mapActions()获取state的各种属性.

export default {

  computed: {

    // gives access to this.counterStore and this.userStore

    ...mapStores(useCounterStore, useUserStore)

    // gives read access to this.count and this.double

    ...mapState(useCounterStore, ['count', 'double']),

  },

  methods: {

    // gives access to this.increment()

    ...mapActions(useCounterStore, ['increment']),

  },

}

eventBus

Vue3不再提供$on与emit函数,Vue实例不再实现事件接口。官方推荐引入外部工具实现,或者自己手撸一个事件类

npm install --save mitt

main.ts中

import mitt from 'mitt'

const eventBus = mitt();

const app = createApp(AppRoot);

app.provide('eventBus', eventBus); // 注入provider

使用:

import { inject } from "vue";

const eventBus: any = inject("eventBus");

watch(

[() => canvasConfig.value.width, () => canvasConfig.value.height],

(resizeVal) => {

eventBus.emit("resize", resizeVal);

}

);

eventBus.on("resize", (arr) => { //所有操作统一通过eventBus监听事件处理

graph.value.resize(arr[0], arr[1]);

});

vue-router4

用法与vue-router3差不多,新增了部分函数

useRoute相当于以前的this.$route

useRouter相当于this.$router

hash模式使用createWebHashHistory

history模式使用createWebHistory

import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'

const router = createRouter({

history: createWebHistory('/ecdesigner'), //base配置.  //ecdesigner 

routes,

})

获取param参数:

1.route.params.id获取

import { useRouter,useRoute } from 'vue-router'  //useRoute相当于以前的this.$route,而useRouter相当于this.$router

setup(props) {

const route = useRoute();

console.log(route.params.id);

const router = useRouter();

router.push({ path: "/screen-editor/" + route.params.id });

}

2.通过props获取 (props设为true, route.params将会被设置为组件属性)

{

path: '/admin/screen/:id,

name: 'ScreenEditor',

props: true,

component: () => import('@/views/screen-editor/index.vue'),

}

setup(props) {

console.log(props.id); //

}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李庆政370

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值