vue项目开发(vue2与vue3对比)

news2024/9/20 14:57:24

在这里插入图片描述

vue中使用typescrip

初与typescrip的约定情愫:最近项目要用到vue3,所以打算使用typescrip语法!
安装:

npx tyarn add typescript @vue/cli-plugin-typescript -D
npx tsc --init

修改 tsconfig.json:

{
  "compilerOptions": {
    "target": "esnext",
    "useDefineForClassFields": true,
    "module": "esnext",
    "moduleResolution": "node",
    "strict": true,
    "jsx": "preserve",
    "sourceMap": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "esModuleInterop": true,
    "lib": ["esnext", "dom"],
    "baseUrl": ".",
    "paths": {
      // "@": ["src"],
      "@/*": ["src/*"],
      "@u/*": ["src/utils/*"],
      "@c/*": ["src/components/*"],
      "@images/*": ["src/assets/images/*"]
    },
    "suppressImplicitAnyIndexErrors": true,
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

将main.js 改为 main.ts:

vue3.0 + vite 多环境打包 代理设置

安装cross-env
cross-env 通过js在平台设置不同的环境变量的工具

npm install --save-dev cross-env

项目根目录新建 .env.development 文件

NODE_ENV = development
VITE_BUILD_ENV = 'development'
VITE_APP_BASE_API = 'http://xxx.xxx.x.xx:xxxx/api' //测试服务器域名

项目根目录新建 .env.production 文件

VITE_ENV = production
VITE_BUILD_ENV = "production"
VITE_APP_BASE_API = "http://xx.snxxx.com" //正式服务器域名

修改package.json

"dev": "cross-env vite --mode development",
"test": "cross-env vite --mode test",
"product": "cross-env vite --mode production",
"build": "vite build",
"build:test": "cross-env vite build --mode test",
"build:product": "cross-env vite build --mode production",
//使用
process.env.NODE_ENV  环境变量(package.json 中定义的变量)
axios.defaults.baseURL = import.meta.env.VITE_APP_BASE_API;
import.meta.env.VITE_APP_BASE_API  请求地址(.env 定义的接口请求地址)
 
//设置代理
import {defineConfig, loadEnv} from 'vite'
import vue from '@vitejs/plugin-vue'
import * as path from 'path';
 
export default ({mode}) => {
    return defineConfig({
        plugins: [vue()],
        resolve: {
            alias: {
                '@': path.resolve(__dirname, './src')//设置别名
            }
        },
        server: {
            port: 3000,//启动端口
            open: true,
            proxy: {
                // 选项写法
                '/api': loadEnv(mode, process.cwd()).VITE_APP_BASE_API //代理网址
            },
            cors: true
        }
    })
}

vite.config.ts

import { defineConfig, loadEnv } from "vite";
import vue from "@vitejs/plugin-vue";
const path = require("path");
import { createStyleImportPlugin } from "vite-plugin-style-import";

export default ({ mode }) =>
  defineConfig({
    base: "./",
    build: {
      terserOptions: {
        // 生产环境移除console
        compress: {
          drop_console: true,
          drop_debugger: true,
        },
      },
      rollupOptions: {
        output: {
          //静态资源分类打包
          chunkFileNames: "assets/js/[name]-[hash].js",
          entryFileNames: "assets/js/[name]-[hash].js",
          assetFileNames: "assets/static/[name]-[hash].[ext]",
          manualChunks(id) {
            //静态资源分拆打包
            if (id.includes("node_modules")) {
              return id
                .toString()
                .split("node_modules/")[1]
                .split("/")[0]
                .toString();
            }
          },
        },
      },
    },
    resolve: {
      alias: {
        // 如果报错__dirname找不到,需要安装node,执行npm install @types/node --save-dev
        "@": path.resolve(__dirname, "src"),
        "@c": path.resolve(__dirname, "src/components"),
        "@u": path.resolve(__dirname, "src/utils"),
        "@images": path.resolve(__dirname, "src/assets/images"),
        "@views": path.resolve(__dirname, "src/views"),
        "@store": path.resolve(__dirname, "src/store"),
      },
    },
    server: {
      open: true, // 是否自动在浏览器打开
      port: 8082,
      host: "10.1.64.104",
      proxy: {
        "/api": {
          target: loadEnv(mode, process.cwd()).VITE_APP_BASEURL,
          changeOrigin: true,
          ws: true,
          rewrite: (path) => path.replace(/^\/api/, ""),
        },
      },
    },
    plugins: [
      vue(),
      createStyleImportPlugin({
        //按需引入vant
        libs: [
          {
            libraryName: "vant",
            esModule: true,
            resolveStyle: (name) => {
              return `/node_modules/vant/es/${name}/style`;
            },
          },
        ],
      }),
    ],
  });

vue2和vue3区别

一、双向数据绑定原理改变

  1. vue2利用es5的API Object.definepropert() 对数据进行劫持,结合发布订阅模式来实现。vue3利用es6 proxyAPI对数据进行处理。
  2. 相比vue2,用proxy API 优势:defineProperty只能监听某个属性,不能对全对象进行监听;可以省去for in 、闭包等内容来提升效率(直接绑定整个对象即可);可以监听数组,不用再去单独对数组做特异性操作,vue3可以检测到数组内部数据的变化。

二、Vue3支持碎片(Fragments)
就是说可以拥有多个跟节点,Template 支持多个根标签。vue2不支持碎片!
Vue 3 有 createApp(),而 Vue 2 的是 new Vue(),createApp(组件),new Vue({template, render})
v-model代替以前的v-model和.sync,vue3中v-model的用法

三、Composition API)
Vue2 与vue3 最大区别是vue2使用选项类型api,对比vue3合成型api。旧的选项型api在代码里分割了不同的属性:data,computed,methods等;新的合成型api能让我们使用方法来分割,相比于旧API使用属性来分组,这样代码会更加简便和整洁。

四、建立数据data
vue2是把数据放入data中,vue3就需要使用一个新的 setup() 方法,此方法在组件初始化构造得时候触发。使用一下三个步骤来简=建立反应性数据:

  1. 从vue引入reactive();使用reactive() 方法来声明数据为响应性数据;
  2. 使用setup()方法来返回我们得响应性数据,从而template可以获取这些响应性数据。

五、生命周期

vue2   --------------------------------   vue3
beforeCreate                        ->   setup()                 -> 实例创建之前
Created                             ->   setup()                 - >实例创建之后
beforeMount                         ->   onBeforeMount           -> DOM挂载前调用
mounted                             ->   onMounted               -> DOM挂载完成调用
beforeUpdate                        ->   onBeforeUpdate          -> 数据更新之前被调用
updated                             ->   onUpdated               -> 数据更新之后被调用
beforeDestroyed                     ->   onBeforeUnmount         -> 中间销毁前调用
destroyed                           ->   onUnmounted             -> 中间销毁完成调用
activated                           ->   onActivated
deactivated                         ->   onDeactivated

六、父子传参不同,setup()函数特性

  • setup()函数接收两个参数:props、context(包含attrs、slots、emit)
  • setup函数是处于生命周期beforeCreated和created俩个钩子函数之前,执行setup时,组件实例尚未被创建(在setup()内部,this不会是该活跃实例得引用,即不指向vue实例,Vue为了避免我们错误得使用,直接将setup函数中得this修改成了undefined)与模板一起使用时,需要返回一个对象因为setup函数中,props是响应式得,当传入新的prop时,它将会被更新,所以不能使用es6解构,因为它会消除prop得响应性,如需解构prop,可以通过使用setup函数中得toRefs来完成此操作。
  • 父传子,用props,子传父用事件 Emitting
    Events。在vue2中,会调用this$emit然后传入事件名和对象;在vue3中得setup()中得第二个参数content对象中就有emit,那么我们只要在setup()接收第二个参数中使用分解对象法取出emit就可以在setup方法中随意使用了。
  • 在setup()内使用响应式数据时,需要通过 .value 获取
import { ref } from 'vue'
const count = ref(0)
console.log(count.value)
  • 从setup() 中返回得对象上得property 返回并可以在模板中被访问时,它将自动展开为内部值。不需要在模板中追加.value。

setup函数只能是同步的不能是异步的。

七、实例化

  1. Vue2中new出的实例对象,所有的东西都在这个vue对象上,这样其实⽆论你⽤到还是没⽤到,都会跑⼀遍,这样不仅提⾼了性能消耗,也⽆疑增加了⽤户加载时间。
  2. ⽽vue3.0中可以⽤ES module,imports按需引⼊,如:keep-alive内置组件、v-model指令,等等,不仅我们开发起来更加的便捷,减少了内存消耗,也同时减少了⽤户加载时间,优化⽤户体验。

八、获取props
vue2在script代码块可以直接获取props,vue3通过setup指令传递

vue2:console.log(‘props’,this.xxx)
vue3:setup(props,context){ console.log(‘props’,props) }

props属性名任意,假设为x;事件名必须为"update:x"

<Switch :value="y" @update:value="y=$event"/>
vue2中的写法
<Switch :value.sync="y"/>
vue3中的写法
<Switch v-model:value="y"/>

九、数据和方法的定义
Vue2使⽤的是选项类型API(Options API),Vue3使⽤的是合成型API(Composition API)

vue2:data() { return {}; }, methods:{ }
vue3: 数据和⽅法都定义在setup中,并统⼀进⾏return{}

十、给父组件传值emit

vue2:this.$emit()
vue3:setup(props,context){context.emit()}

十一、watchEffect
Vue3中除了watch,还引入了副作用监听函数watchEffect,用过之后我发现它和React中的useEffect很像,只不过watchEffect不需要传入依赖项。

watchEffect它会立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。

computed和watch所依赖的数据必须是响应式的。Vue3引入了watchEffect,watchEffect 相当于将 watch 的依赖源和回调函数合并,当任何你有用到的响应式依赖更新时,该回调函数便会重新执行。不同于 watch的是watchEffect的回调函数会被立即执行,即({ immediate: true })。

十二、组件通信

                                vue2   --------------------------  vue3
父传子                        -> props                           -> props
子传父                        -> $emit                           -> $emit 
子组访问父组件                 -> $parent                         -> 无
父组访问子组件                 -> $ref                            -> expose$ref
兄弟传值                       -> EventBus                        -> mitt

注意:
props中数据流是单项的,即子组件不可改变父组件传来的值
在组合式API中,如果想在子组件中用其它变量接收props的值时需要使用toRef将props中的属性转为响应式。

十三、路由
vue2写法:

<script>
export default {
  beforeRouteEnter (to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    next()
  },
  beforeRouteEnter (to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    next()
  },
  beforeRouteLeave ((to, from, next)=>{//离开当前的组件,触发
    next()       
  }),
  beforeRouteLeave((to, from, next)=>{//离开当前的组件,触发
    next()      
  }),
  methods:{
    toPage(){
      //路由跳转
      this.$router.push(xxx)
    }
  },
  created(){
    //获取params
    this.$route.params
    //获取query
    this.$route.query
  }
}
</script>

vue3的beforeRouteEnter作为路由守卫的示例是因为它在setup语法糖中是无法使用的;大家都知道setup中组件实例已经创建,是能够获取到组件实例的。而beforeRouteEnter是再进入路由前触发的,此时组件还未创建,所以是无法用在setup中的;如果想在setup语法糖中使用则需要再写一个script 如下:

<script>
export default {
  beforeRouteEnter(to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    next()
  },
};
</script>

vue3路由写法:

<script>
import { defineComponent } from 'vue'
import { useRoute, useRouter } from 'vue-router'
export default defineComponent({
  beforeRouteEnter (to, from, next) {
    // 在渲染该组件的对应路由被 confirm 前调用
    next()
  },
  beforeRouteLeave ((to, from, next)=>{//离开当前的组件,触发
    next()       
  }),
  beforeRouteLeave((to, from, next)=>{//离开当前的组件,触发
    next()      
  }),
  setup() {
    const router = useRouter()
    const route = useRoute()
    const toPage = () => {
      router.push(xxx)
    }
 
    //获取params 注意是route
    route.params
    //获取query
    route.query
    return {
      toPage
    }
  },
});
</script>

十四、context.emit
新增context.emit,与this.$emit(vue3中只能在methods里使用)作用相同

import {SetupContext } from 'vue'
setup(props: Prop, context: SetupContext) {
    const toggle = () => {
      context.emit('input', !props.value)
    }
    return {toggle}
}

十五、slot具名插槽
vue2:

//子组件:
<slot name="title">

//父组件:
<template slot="title">
  <h1>哈哈哈</h1>
</template>

vue3:

```bash
//子组件:
<slot name="title">

//父组件:
<template v-slot:title>
  <h1>哈哈哈</h1>
</template>

十六、vue3中ref

//单个:
<script>
import {onMounted, ref,} from 'vue';

export default {
  setup() {
    const headline = ref(null);
    // Before the component is mounted, the value
    // of the ref is `null` which is the default
    // value we've specified above.
    onMounted(() => {
      // Logs: `Headline`
      console.log(headline.value.textContent);
    });
    return {
      // It is important to return the ref,
      // otherwise it won't work.
      headline,
    };
  },
};
</script>

<template>
  <div>
    <h1 ref="headline">
      Headline
    </h1>
    <p>Lorem ipsum ...</p>
  </div>
</template>
//v-for里的ref
<template>
  // el当前元素,divs是存储每个元素的数组
  <div v-for="(item, index) in list" :ref="el => { divs[index] = el }">
    {{ item }}
  </div>
</template>

<script>
import {onMounted, ref,} from 'vue';

export default {
  setup() {
    const divs = ref([]);
    onMounted(() => {
      console.log(divs.value)
    });
    return {
      divs
    };
  },
};
</script>

十七、watchEffect

watchEffect用来代替生命周期里的onMounted和onUpdated,初始化页面的时候watchEffect里的代码会执行,当watchEffect里的数据有更新的时候同样会执行

const count = ref(0)

watchEffect(() => console.log(count.value))
// -> logs 0

setTimeout(() => {
  count.value++
  // -> logs 1
}, 100)

注意watchEffect第一次运行是在组件挂载之前,如果需要访问DOM需要将我们的watchEffect放在onMounted里

onMounted(() => {
  watchEffect(() => console.log(count.value))
})

十八、…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/358822.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LVS中的keepalived高可用

文章目录前言一、Keepalived简介二、keepalived工作原理三、配置文件四、实验1.某台Real Server down2.LVS本身down实验过程&#xff1a;五、代码详细演示整体过程调度器安装软件、设置测试keepalived对后端RS的健康检测backup服务主机设置前言 一、Keepalived简介 Keepalived是…

ubuntu18.4安装Redmine软件

1.github网站下载Redmine4.2.0的安装包&#xff0c;如下图所示&#xff1a; https://github.com/redmine/redmine/releases/tag/4.2.0 图1 github网站下载redmine4.2.0安装包2.拷贝Redmine4.2.0的安装包到ubuntu工作目录&#xff0c;并解压缩&#xff0c;如下所示&#xff1a;…

Springboot前后端分离国际化实现-chatgpt

前言 Springboot国际化可以帮助使用者在不同语言环境中构建应用程序&#xff0c;这样应用程序可以有效地适应不同语言文化背景下的用户需求。 此外&#xff0c;Springboot国际化也可以方便多语言应用程序重用和维护&#xff0c;从而减少了系统部署的时间成本和维护的费用。 要实…

医疗方案 | 星辰天合入选“2022智慧新医信优秀解决方案”

近日&#xff0c;由 HC3i数字医疗网主办的《数字化转型驱动下的医院高质量发展论坛》暨 2022 智慧新医信优秀解决方案发布仪式在线上召开。XSKY星辰天合的“智慧医疗软件定义数据基础设施”解决方案成功入选 2022 智慧新医信优秀解决方案&#xff0c;。此次论坛由 HC3i 数字医疗…

会利用信息差赚钱的人才是聪明人

毕业后找不到工作&#xff0c;穷到只剩下时间&#xff0c;大小做了20多份副业兼职&#xff0c;终于找到了可靠的渠道&#xff0c; 我是专科生&#xff0c;学历不好&#xff0c;专业拉胯。毕业后&#xff0c;我找了两三份工作。要么工资太低&#xff0c;只能交房租&#xff0c;…

javaFx实现鼠标穿透画布,同时操作画布和桌面,背景透明,类似ppt批注

一、功能需要由来和大致效果 今天&#xff0c;我们要用javaFx来实现一个鼠标穿透画布的功能&#xff0c;该需求来自于在我们的javaFx桌面应用中&#xff0c;需要实现一个悬浮的桌面侧边工具栏&#xff0c;在工具栏中有画笔绘制&#xff0c;批注的功能&#xff0c;能够实现在任何…

【NLP】一种联合关系抽取模型——TPLinker

背景 前文介绍了【NLP】一种基于联合方式的三元组抽取模型——CasRel.这个模型虽然实体和关系同时训练&#xff0c;但本质上来说还是分阶段的预测实体和关系&#xff0c;依然存在暴露偏差问题。下面介绍一个解决暴露偏差的模型&#xff1a;TPLinker&#xff0c;论文地址&#…

【OJ】A+B=X

&#x1f4da;Description: 数列S中有n个整数&#xff0c;判断S中是否存在两个数A、B&#xff0c;使之和等于X。 ⏳Input: 第一行为T&#xff0c;输入包括T组测试数据。 每组数据第一行包括两个数字n和X&#xff0c;第二行有n个整数&#xff0c;表示数列S&#xff0c;(1&l…

Linux-0.11 文件系统inode.c详解

Linux-0.11 文件系统inode.c详解 Linux-0.11中使用的文件系统为minix&#xff0c; inode.c中的函数和该文件系统强关联。 inode节点在文件系统中与文件相关联&#xff0c;一个文件的就由一个inode来管理&#xff0c;这个inode节点将记录文件的权限&#xff0c;大小&#xff0…

SpringCloud之Nacos

Nacos1. Nacos的概念2. Nacos的作用3. Nacos的下载与安装4. Nacos Client 服务端的搭建5. Nacos 的namespace 和 group6. 配置中心7. 注意点1. Nacos的概念 Nocos 是 SpringCloudAlibaba架构中最重要的组件Nacos 是一个更易于帮助构建云原生应用的动态服务发现、配置和服务挂你…

pytorch搭建手写数字识别LeNet-5网络,并用tensorRT部署

pytorch搭建手写数字识别LeNet-5网络&#xff0c;并用tensorRT部署前言1、pytorch 搭建LeNet-5&#xff0c;并转为ONNX格式1.1 LeNet-5网络介绍1.2 ONNX(Open Neural Network Exchange)介绍1.3 pytorch 搭建 LeNet5网络2、将onnx转为tensorRT2.1 tensorRT 介绍2.1 onnx 转为 te…

C++面向对象(下)

文章目录前言1.再谈构造函数1.初始化列表2.explicit关键字2. static成员1.概念3.友元1.概念2.友元函数3.友元类4. 内部类5.匿名对象6.编译器优化7.总结前言 本文是主要是将之前关于C面向对象中的一些没有归纳到的零星知识点进行补充&#xff0c;同时对C中的面向对象简单收个尾…

如何在ONLYOFFICE v7.3中使用VSTACK和HSTACK公式

大家好&#xff0c;今天来给大家讲解一下&#xff0c;怎样在ONLYOFFICE v7.3中使用VSTACK和HSTACK公式&#xff0c; 这两个新公式也是ONLYOFFICE7.3版本更新后新的计算公式&#xff0c;请大家详细阅读本文。 ONLYOFFICE ONLYOFFICE文档是一款免费开源在线办公软件&#xff0c…

实验室装修|SICOLAB实验室装修方案

实验室装修不外乎通风与洁净的设计为重中之重&#xff0c;以下由SICOLAB介绍分享。一、实验室通风系统主要包含送风系统和排风系统两部分。&#xff08;1&#xff09;送风系统的设计需要考虑以下几个方面&#xff1a;1.1空气质量要求&#xff1a;实验室内的空气需要保持一定的洁…

生物素标记试剂1869922-24-6,Alkyne-PEG3-Biotin PC,炔烃PEG3生物素PC

1、试剂基团反应特点&#xff08;Reagent group reaction characteristics&#xff09;&#xff1a;PC alkyne-PEG3-Biotin含一个炔烃和一个 PEG 链接的可光裂解生物素基团。含 3 个单元 PEG 的 ADC linker&#xff0c;生物素本身是个游离的小分子&#xff0c;在生物实验中常常…

【汽车雷达通往自动驾驶的关键技术】

本文编辑&#xff1a;调皮哥的小助理 现代汽车雷达装置比手机还小&#xff0c;能探测前方、后方或侧方的盲点位置是否存在障碍物&#xff0c;但这还不百分之百实现全自动驾驶的。传统的汽车雷达分辨率都不高&#xff0c;只能“看到”一团东西&#xff0c;可以检测到汽车周围存在…

掌握使用yum为CentOS系统安装软件掌握使用apt为Ubuntu安装软件(扩展)

1.掌握使用yum为CentOS系统安装软件2.掌握使用apt为Ubuntu安装软件&#xff08;扩展&#xff09;1、Linux系统的应用商店 操作系统安装软件有许多种方式&#xff0c;一般分为&#xff1a; •下载安装包自行安装•如win系统使用exe文件、msi文件等•如mac系统使用dmg文件、pkg文…

容联七陌:ChatGPT大模型能力为智能客服带来新方向

科技云报道原创。 近几个月来&#xff0c;大众对ChatGPT预期的持续走高&#xff0c;也影响到了智能客服领域公司的命运。 一方面&#xff0c;ChatGPT的出现为智能客服场景带来了更加“智能”的可能性&#xff1b;但另一方面&#xff0c;有人认为ChatGPT完全可以替代现有的智能…

数值方法笔记3:线性和非线性方程组求解

前置知识1&#xff1a;矩阵范数前置知识2&#xff1a;舒尔补前置知识3&#xff1a;可约矩阵前置知识4&#xff1a;谱半径1.【线性方程组】直接求解&#xff1a;高斯消元法(LULULU分解)、LDVLDVLDV分解、LDLTLDL^TLDLT分解、UDUTUDU^TUDUT分解1.1 高斯消元法(LULULU分解)1.2 LDV…

公司缺人面了8个测试员,他们都有一个相同的缺点.....

年后公司缺人&#xff0c;面了不少测试&#xff0c;结果竟然没有一个合适的。 一开始瞄准的就是中级的水准&#xff0c;也没指望来大牛&#xff0c;提供的薪资在10-20k&#xff0c;面试的人很多&#xff0c;但平均水平很让人失望。 看简历很多都是3年工作经验&#xff0c;但面…