IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 实践总结|vue2升级vue3全面对照迁移示例 -> 正文阅读

[JavaScript知识库]实践总结|vue2升级vue3全面对照迁移示例

前言

自从vue3 <script setup> 语法糖出现后,我的个人小项目和毕业设计都开始使用 vue3+ts 进行开发,在经历了很多的业务开发和踩坑经历后,我将vue2项目迁移升级vue3写了一个阶段性总结!

请大家在真正进行项目迁移前务必先看下官方迁移的文档,以下内容尽量讲vue官方文档中比较难找到或者没有讲过的内容。

vue2迁移vue3官网文档介绍

以下内容和示例统一使用的是 vue3 composition api <script setup> 语法糖的写法,我会使用简单的例子和官方文档对应位置的的链接让大家快速理解的。

开发准备

首先如果你是用的是vscode进行vue2的开发,我相信你一定会安装vetur这个拓展插件,我们要做的第一件事是安装一个新的拓展插件 volar , volar 是官方的一个vue3代码提示插件。

具体的插件介绍之后单独出,这期不是重点,但是请务必安装这个拓展后再进行vue3的开发噢!

单文件组件

响应式变量声明

vue2写法

<!-- vue2写法 -->
<template>
  <div>
    {{ a }}
    {{ b.c }}{{ b.d }}
  </div>
</template>

<script>
export default {
  data() {
    return {
      a: "我是oil",
      b: {
        c: "我是张三",
        d: "我是赵四",
      },
    }
  },
}
</script>

vue3写法

<!-- vue3写法 -->
<template>
  <div>
    {{ a }}
    {{ b.c }}{{ b.d }}
  </div>
</template>

<script setup lang="ts">
import { ref, reactive } from "vue"
const a = ref("我是oil")
const b = reactive({
  c: "我是张三",
  d: "我是赵四",
})
</script>

<style lang="scss" scoped></style>

在vue3中响应式变量用 refreactive 两个api来定义,reactive用来定义对象,ref用来定义除了对象的其他数据类型。

reactive api官方介绍

ref api官方介绍

watch,computed及生命周期

vue2写法

<!-- vue2写法 -->
<template>
  <div>
    {{ a }}
    <!-- 我是oil -->
    {{ computedA }}
    <!-- 其实我是oil -->
  </div>
</template>

<script>
export default {
  data() {
    return {
      a: "我是oil",
    }
  },
  watch: {
    a: {
      handler() {
        console.log(this.a)
      },
      immediate: true,
      deep: true,
    },
  },
  computed: {
    computedA() {
      return "其实" + this.a
    },
  },
  mounted() {
    this.a = "我不是oi"
  },
}
</script>


vue3写法

<!-- vue3写法 -->
<template>
  <div>
    {{ a }}
    <!-- 我是oil -->
    {{ computedA }}
    <!-- 其实我是oil -->
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, watch, computed } from "vue"
const a = ref("我是oil")
watch(
  () => a.value,
  () => {
    console.log(a.value)
  },
  { immediate: true }
)
const computedA = computed(() => "其实" + a.value)
onMounted(() => {
  a.value = "我不是oil"
})
</script>


在vue3中,生命周期computedwatch 都是通过传入回调方法进行方法声明的。具体的使用方法可以看上面的示例和官方的介绍

computed周期 官方文档

watch api官方文档

生命周期 官方文档

父组件向子组件传值

vue2写法

子组件

<!-- vue2子组件 -->
<template>
  <div>
    {{ a }}
    <!-- 我是oil -->
    {{ computedA }}
    <!-- 其实我是oil -->
  </div>
</template>

<script>
export default {
  props: {
    a: {
      type: String,
    },
  },
}
</script>

父组件

<!-- vue2父组件 -->
<template>
  <div>
    <vue2-child></vue2-child>
    <!-- 我是oil -->
  </div>
</template>

<script>
import Vue2Child from "./vue2-child.vue"
export default {
  data() {
    return {
      a: "我是oil",
    }
  },
  components: {
    Vue2Child,
  },
}
</script>

vue3写法

子组件

<!-- vue3子组件 -->
<template>
  <div>
    {{ a }}
    <!-- 我是oil -->
  </div>
</template>

<script setup lang="ts">
import { onMounted, defineProps } from "vue"
const props = defineProps({
  a: String,
})

onMounted(() => {
  console.log(props.a)
})
</script>

父组件

<!-- vue3父组件 -->
<template>
  <div>
    <vue3-child :a="a"></vue3-child>
    <!-- 我是oil -->
  </div>
</template>

<script setup lang="ts">
import vue3Child from "./vue3-child.vue"
import { ref } from "vue"

const a = ref("我是oil")
</script>

首先展示的是最传统的通过props传值的写法,在vue3中的变化为通过defineProps这个api来定义参数值,且组件的引入无需局部注册,可以直接使用

defineProps api官方文档

通过ref实现子组件向父组件传值

vue2 写法

子组件

<!-- vue2子组件 -->
<template>
  <div>
    {{ a }}
    <!-- 我是oil -->
    {{ computedA }}
    <!-- 其实我是oil -->
  </div>
</template>

<script>
export default {
  props: {
    a: {
      type: String,
    },
  },
  data() {
    return {
      b: "这个是我想给父组件的值",
    }
  },
}
</script>

父组件

<!-- vue2父组件 -->
<template>
  <div>
    <vue2-child ref="childRef"></vue2-child>
    <!-- 我是oil -->
  </div>
</template>

<script>
import Vue2Child from "./vue2-child.vue"
export default {
  data() {
    return {
      a: "我是oil",
    }
  },
  components: {
    Vue2Child,
  },
  mounted() {
    console.log(this.$refs.childRef.b)
  },
}
</script>


vue3 写法

子组件

<!-- vue3子组件 -->
<template>
  <div>
    {{ a }}
    <!-- 我是oil -->
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted, defineProps, defineExpose } from "vue"
const props = defineProps({
  a: String,
})
const b = ref("这个是我想给父组件的值")
onMounted(() => {
  console.log(props.a)
})
defineExpose({
  b,
})
</script>

父组件

<!-- vue3父组件 -->
<template>
  <div>
    <vue3-child :ref="childRef" :a="a"></vue3-child>
    <!-- 我是oil -->
  </div>
</template>

<script setup lang="ts">
import vue3Child from "./vue3-child.vue"
import { ref, onMounted } from "vue"
const childRef = ref()
const a = ref("我是oil")

onMounted(() => {
  console.log(childRef.value.b) // "这个是我想给父组件的值"
})
</script>

通过以上例子的对比,在vue2中如果父组件想要拿到子组件的值可以通过$ref 被来给元素或子组件注册引用信息,通过childRef指向引用组件实例,这样我们可以获取到子组件上的属性

在vue3中,使用 <script setup> 的组件是默认关闭的,也即通过模板 ref 或者 $parent 链获取到的组件的公开实例,不会暴露任何在 <script setup> 中声明的绑定。所以我们需要通过 defineExpose 将子组件中的变量暴露出去才能在父组件中获取到!

ref api官方文档

defineExpose api官方文档

通过emit实现子组件向父组件传值

vue2写法

子组件

<!-- vue2子组件 -->
<template>
  <div>
    {{ a }}
    <!-- 我是oil -->
    {{ computedA }}
    <!-- 其实我是oil -->
  </div>
</template>

<script>
export default {
  props: {
    a: {
      type: String,
    },
  },
  data() {
    return {
      b: "这个是我想给父组件的值",
    }
  },
  mounted() {
    this.$emit("emitFunc", this.b)
  },
}
</script>


父组件

<!-- vue2父组件 -->
<template>
  <div>
    <vue2-child @emitFunc="getEmit"></vue2-child>
    <!-- 我是oil -->
  </div>
</template>

<script>
import Vue2Child from "./vue2-child.vue"
export default {
  data() {
    return {
      a: "我是oil",
    }
  },
  components: {
    Vue2Child,
  },
  getEmit(data) {
    console.log(data) // "这个是我想给父组件的值"
  },
}
</script>

vue3写法

子组件

<!-- vue3子组件 -->
<template>
  <div></div>
</template>

<script setup lang="ts">
import { ref, onMounted, defineEmits } from "vue"
const emit = defineEmits(["emitFunc"])
const b = ref("这个是我想给父组件的值")
onMounted(() => {
  emit("emitFunc", b.value)
})
</script>

父组件

<!-- vue3父组件 -->
<template>
  <div>
    <vue3-child @emitFunc="getEmit"></vue3-child>
  </div>
</template>

<script setup lang="ts">
import vue3Child from "./vue3-child.vue"
const getEmit = (data: string) => {
  console.log(data) // "这个是我想给父组件的值"
}
</script>

在vue3中实现子组件触发父组件的方法并传值给父组件需要通过defineEmits api来实现,上面的例子通过emit定义了一个 emitFunc 方法,在定义后我们可以通过emit方法传入一个参数来触发指定的事件。

defineEmits api官方介绍

通过project 和 inject实现爷孙组件传值

vue3写法

孙子组件

<!-- vue3孙组件 -->
<template>
  <div>
    {{ a }}
  </div>
</template>

<script setup lang="ts">
import { inject } from "vue"
const a = inject("grandpaData")
</script>

爷爷组件

<!-- vue3爷组件 -->
<template>
  <div>
    <vue3-child></vue3-child>
  </div>
</template>

<script setup lang="ts">
import { provide } from "vue"
provide("grandpaData", "我是来自爷爷的值")
</script>

无论在vue2还是在vue3中都有可能涉及到变量需要跨多个组件传递的问题,这个实现的方法其实有很多种,上面的示例展示的是通过projectinject实现.

实际开发中不仅可以通过 vuexlocalstorage这种定义全局变量的方式实现,还可以通过一层一层的去写props传递参数或通过 p a r e n t , parent, parent,ref 的方式来拿到跨多组件的值,根据实际业务出发才是最好的。

抽离组件逻辑代码,实现模块化

vue2实现mixin

业务逻辑代码

// Vue2Mixin.js
export default {
  data() {
    return {
      b: "我是vue2的mixin中的值"
    }
  },
  mounted() {
    console.log("我被放在mixin中了,这样可以减少我的代码")
  }
}

组件代码

<!-- vue2组件 -->
<template>
  <div>{{b}}</div>
</template>

<script>
import Vue2Mixin from "./Vue2Mixin"
export default {
  data() {
    return {
      a: "我是oil",
    }
  },
  mixins: [Vue2Mixin],
}
</script>

如上示例,在vue2中我们可以通过mixin api来抽离分类一些业务代码,简化我们组件中的代码,但是要注意 变量名重复等一些问题

vue3实现hook

业务逻辑代码

//hook.ts
import { ref, onMounted } from "vue"
export default function useHook() {
  const b = ref("我是vue3的hook中的值")
  onMounted(() => {
    console.log("我被放在hook中了,这样可以减少我的代码")
  })
  return { b }
}

组件代码

<!-- vue3组件 -->
<template>
  <div>
    {{ b }}
  </div>
</template>

<script setup lang="ts">
import useHook from "./hook"
const { b } = useHook()
</script>

如上示例,在vue3中我们可以通过写 hook 的方式来抽离分类一些业务代码,简化我们组件中的代码。

咱们可以和 mixin 对比一下看看,咱们在两个例子中都将 变量b 给抽离出去了,然后通过不同的方式引入,但是在 mixin 中我们是不能看到具体引入那些值的,而使用hook的话就非常的清晰,也可以避免变量名重复的情况!

vue2 css穿透scoped作用域

<style lang="scss" scoped>
/deep/.el-upload-dragger {
  width: 20rem;
}
/deep/.el-upload-list__item {
  margin: 0;
}
</style>

vue2中使用 /deep/ + 选择器名称 进行深层样式穿透scoped选中

vue3 css穿透scoped作用域

<style lang="scss" scoped>
deep(.el-upload-dragger) {
  width: 20rem;
}
deep(.el-upload-list__item) {
  margin: 0;
}
</style>

vue2中使用 deep(选择器名称) 进行深层样式穿透scoped选中

总结

vue3相比vue2来说迁移的难度和纬度是根据个人能力而定的,在vue3中你大可以类似vue2一样使用option API的方式来写代码,但是既然要升级,咱们就要追求一个最佳实践嘛。

而且使用 componsition api 的话对ts的支持更加友好噢,所以建议如果要升级vue3的话就直接使用 script setup 的语法再加上 typescript绝对给你远超vue2的开发体验噢

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-30 12:28:21  更:2021-10-30 12:29:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:35:51-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码