Vue2.0和3.0区别(总结版,不断更新)

本文对比了Vue2.0和3.0在安装、项目初始化、目录结构、main.js、路由配置、setUp()函数等方面的区别。Vue3.0引入了setup函数,简化组件编写,同时移除了部分2.0中的配置文件,如环境变量配置和webpack配置文件。此外,路由组件不再需要单一根节点,计算属性和生命周期函数也发生了变化。

一 安装及版本切换

查看当前版本,如果是2开头说明当前使用的是vue-cli2,3开头的话就是vue-cli4

vue --version

如果无法识别vue命令说明没有安装vue-cli,使用以下说明进行安装
安装3.0版本:

npm install -g vue-cli

安装3.0版本:

npm install -g @vue/cli

版本切换,即卸载当前版本,安装另外的版本
从2.0升级到3.0:

npm uninstall -g vue-cli
npm install -g @vue/cli

从3.0降到2.0:

npm uninstall -g @vue/cli
npm install -g vue-cli

二 项目初始化

2.0初始化,vue init <模板名称(webpack比较常用)> [项目名称]

vue init webpack cli2-test

2.0项目初始化参数介绍

//项目名称
 Project name ...
 //作者的信息,会默认从git中读取信息
 Project description ...
 Author ...
 //vue build的选项 1.runtime-compiler   2.runtime-only (一般选第一个就好)
 vue build ...
 //是否安装vue-router,一般选用YES,省去手动创建路由
 Install vue-router? ..
 //是否使用ESLint检测代码规范,规范可根据选项选择不同的规范库或者自己添加规范
 use ESLint to link your code
 //是否写单元测试 (一般不使用)
 Set up unit tests
 //是否使用Nightwatch来进行e2e测试 (2代表to  e to e 点对点)
 Setup e2e test with Nightwatch?
 //使用npm或者yarn包管理工具
 use npm
 use yarn

 

3.0初始化,vue create [项目名称]

vue create cli3-test

4.0项目初始化参数介绍

//选择一个配置方式
 please pick a perset  (一般选最后一个Manually select features(手动选择特性) )
 //选择对于你的工程所需要的特性 (用空格选择)
 check the features needed for your project
( ) Babel //转码器,可以将ES6代码转为ES5代码,从而在现有环境执行。 
( ) TypeScript// TypeScript是一个JavaScript(后缀.js)的超集(后缀.ts)包含并扩展了 JavaScript 的语法,需要被编译输出为 JavaScript在浏览器运行,目前较少人再用
( ) Progressive Web App (PWA) Support// 渐进式Web应用程序
( ) Router // vue-router(vue路由)
( ) Vuex // vuex(vue的状态管理模式)
( ) CSS Pre-processors // CSS 预处理器(如:less、sass)
( ) Linter / Formatter // 代码风格检查和格式化(如:ESlint)
( ) Unit Testing // 单元测试(unit tests)
( ) E2E Testing // e2e(end to end) 测试
 //对应的配置文件单独生成还是放在package.json里
 where do you prefer placing config for babel
 //要不要把刚才自己选择的配置保存下来
 save this as a preset for future projects?

三 目录结构对比

2.0目录结构

3.0目录结构

对比一下两种方式初始化出来的项目结构,下面说一些对我们开发影响比较大的主要的变化

3.0版本中项目环境变量配置文件没有了(dev.env.js / prod.env.js)
我们可以通过在项目根目录下手动创建不同环境的配置文件,具体的环境变量名称由package.json中运行参数决定,下面举个例子添加development、production和uat版本的环境变量:

//  .env.delelopment
NODE_ENV=development
VUE_APP_MODE=development
BASE_URL=/develop

// .env.production
NODE_ENV=production
VUE_APP_MODE=production
BASE_URL=/api

// .env.uat
NODE_ENV=production
VUE_APP_MODE=uat
BASE_URL=/uat
// package.json
----
"scripts": {
   "serve": "vue-cli-service serve",
   "build:uat": "vue-cli-service build --mode uat", // 通过 --mode来运行不同的环境,自动识别到.env.uat配置文件
   "build:production": "vue-cli-service build --mode production",
   "lint": "vue-cli-service lint"
 },
 ----

3.0版本中不同环境的webpack配置文件也没有了(webpack.base.conf.js / webpack.dev.conf.js / webpack.prod.conf.js)
同样,我们也可以再根目录中创建vue.config.js文件来进行webpack和vue的一些配置

const path = require('path')

module.exports = {
 publicPath: './', // 基本路径,打包时加上.
 outputDir: process.env.outputDir, // 输出文件目录
 lintOnSave: false, // eslint-loader 是否在保存的时候检查
 // see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md
 // webpack配置
 chainWebpack: (config) => {
   config.resolve.symlinks(true)
 },
 configureWebpack: (config) => {
   if (process.env.VUE_APP_MODE === 'production') {
     // 为生产环境修改配置...
     config.mode = 'production'
   } else {
       // 为开发环境修改配置...
       config.mode = 'development'
   }
   Object.assign(config, {
     // 开发生产共同配置
     resolve: {
       alias: {
         '@': path.resolve(__dirname, './src'),
         '@c': path.resolve(__dirname, './src/components'),
         '@p': path.resolve(__dirname, './src/views')
       } // 别名配置
     }
   })
 },
 productionSourceMap: false, // 生产环境是否生成 sourceMap 文件
 // css相关配置
 css: {
   // extract: true, // 是否使用css分离插件 ExtractTextPlugin
   sourceMap: false, // 开启 CSS source maps?
   loaderOptions: {
     css: {}, // 这里的选项会传递给 css-loader
     less: {
       modifyVars: {
         // less vars,customize ant design theme

         // 'primary-color': '#F5222D',
         // 'link-color': '#F5222D',
         // 'border-radius-base': '4px'
       },
       // DO NOT REMOVE THIS LINE
       javascriptEnabled: true
     },
     postcss: {
       plugins: [
         // 把px单位换算成rem单位
         require('postcss-pxtorem')({
           rootValue: 75, // 换算的基数(设计图750的根字体为32)
           selectorBlackList: ['.van-'], // 要忽略的选择器并保留为px。
           propList: ['*'], // 可以从px更改为rem的属性。
           minPixelValue: 2 // 设置要替换的最小像素值。
         }),
         require('autoprefixer')
       ]
       // plugins: [
       //   require('autoprefixer')
       // ]
     } // 这里的选项会传递给 postcss-loader
   }, // css预设器配置项 详见https://cli.vuejs.org/zh/config/#css-loaderoptions
   // modules: false, // 启用 CSS modules for all css / pre-processor files.
   requireModuleExtension: true
 },
 parallel: require('os').cpus().length > 1, // 是否为 Babel 或 TypeScript 使用 thread-loader。该选项在系统的 CPU 有多于一个内核时自动启用,仅作用于生产构建。
 pwa: {}, // PWA 插件相关配置 see https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa
 // webpack-dev-server 相关配置
 devServer: {
   open: false, // 自动打开浏览器
   host: '0.0.0.0', // 允许外部ip访问
   port: 8000, // 端口
   https: false, // 启用https
   overlay: {
     warnings: true,
     errors: true
   }, // 错误、警告在页面弹出
   // proxy: 'http://localhost:4000' // 配置跨域处理,只有一个代理
   proxy: {
       '/api': {
           target: '<url>',
           ws: true,
           changeOrigin: true
       },
       '/foo': {
           target: '<other_url>'
       }
   },  // 配置多个代理
 },
 // 第三方插件配置
 pluginOptions: {}
}

四 main.js 文件

import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')

五 路由router文件

// 可以根据路由模式的不同,后面俩可以只引用一个
import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
import Home from '@/views/Home.vue'

// 构建我们的页面路由配置,可以看到,这里和原来的写法并无二致。
const routes = [
  {
    path: '/',
    component: Home
  }, {
    path: '/about',
    component: () => import('@/views/About.vue'),
  }
]

const router = createRouter({
  // 使用 hash 模式构建路由( url中带 # 号的那种)
  history: createWebHashHistory(),
  // 使用 history 模式构建路由 ( url 中没有 # 号,但生产环境需要特殊配置)
  // history: createWebHistory(),
  routes
})
export default router

得益于 vue3.0 的特性,我们现在不比把组件内容全部包裹在某一个 div 下面了,一个 template 里面可以有多个根节点元素,是没有关系的。

About.vue

<template>
  这里是关于我们的页面
  <router-link to="/">点这里去首页</router-link>
</template>

App.vue

<template>
  <router-view />
</template>

在main.js挂载

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

// 将创建的 App 搞个别名
const app = createApp(App)

// 使用路由配置
app.use(router)

// 挂载运行
app.mount('#app')

六 setUp()函数

①Home.vue

<template>
  <router-link to="/about">点这里去关于我们页面</router-link>
  <div class="home">
    这里是一个计数器 >>> <span class="red">{{count}}</span> <br>
    <button @click="countAdd">{{btnText}}</button>
  </div>
</template>

<script>
// ref 是 vue 3.0 的一个重大变化,其作用为创建响应式的值
import { ref } from 'vue'
// 导出依然是个对象,不过对象中只有一个 setup 函数
export default {
  setup () {
    // 定义一个不需要改变的数据
    const btnText = '点这个按钮上面的数字会变'
    // 定义一个 count 的响应式数据,并赋值为 0
    const count = ref(0)
    // 定义一个函数,修改 count 的值。
    const countAdd = () => {
      count.value++
    }
    // 导出一些内容给上面的模板区域使用
    return {
      btnText,
      count,
      countAdd
    }
  }
}
</script>
<style lang="scss">
.home {
  line-height: 2;
  .red {
    color: red;
  }
}
</style>

首先,我们的组件不用写一堆东西了,只需要一个 setup 函数即可。

这样做得好处就是,我们可以把很多零碎的东西拆成公共组件,然后交给其他组件去调用。我写 vue 有一个痛苦的点就是很多的东西我想抽离成组件,但是一拆,就得有 data (), methods 等等一堆。因此,有时候就偷懒,懒得拆了。

现在好了,可以一个函数就是一个组件,多方便啊!

其次,在 setup 函数中 return 出去的东西,可以在模板区域直接使用,也不必理会 this 这个神奇的东西。

然后就是 ref 这个函数,我们可以从 vue 中引入它,它传入一个值作为参数,返回一个基于该值的 响应式 Ref 对象,该对象中的值一旦被改变和访问,都会被跟踪到,通过修改 count.value 的值,可以触发模板的重新渲染,显示最新的值。
 

②about.vue关于reactive

<template>
  <router-link to="/">点这里去首页</router-link>
  <hr>
  <dl>
    <dt>{{state.name}}</dt>
    <dd>性别:{{state.sex}}</dd>
    <dd>地址:{{state.address}}</dd>
  </dl>
  <button @click="addressChange">更新地址</button>
</template>
<script>
// reactive 是 vue 3.0 的一个重大变化,其作用为创建响应式的对象或数组
import { reactive } from 'vue'
// 导出依然是个对象,不过对象中只有一个 setup 函数
export default {
  setup () {
    // 定义一个 state 的响应式对象数据,并赋值
    const state = reactive({
      name: 'FungLeo',
      sex: 'boy',
      address: '上海'
    })
    console.log(state)
    // 定义一个函数,修改 state 的值。
    const addressChange = () => {
      state.address += '浦东'
    }
    // 导出一些内容给上面的模板区域使用
    return {
      state,
      addressChange
    }
  }
}
</script>

reactive 和 ref 的区别就是,reactive 是处理对象或者数组的。

③生命周期函数:

2.0 周期名称3.0 周期名称说明
beforeCreatesetup组件创建之前
createdsetup组件创建完成
beforeMountonBeforeMount组件挂载之前
mountedonMounted组件挂载完成
beforeUpdateonBeforeUpdate数据更新,虚拟 DOM 打补丁之前
updatedonUpdated数据更新,虚拟 DOM 渲染完成
beforeDestroyonBeforeUnmount组件销毁之前
destroyedonUnmounted组件销毁后

life.vue

<template>
  <router-link to="/">点这里去首页</router-link>
  <hr>
  <div class="home">
    这里是一个计数器 >>> <span class="red">{{count}}</span> <br>
    <button @click="countAdd">点击加数字</button>
  </div>
</template>
<script>
// 你需要使用到什么生命周期,就引出来什么生命周期
import {
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  ref
} from 'vue'

export default {
  // setup 函数,就相当于 vue 2.0 中的 created
  setup () {
    const count = ref(0)
    // 其他的生命周期都写在这里
    onBeforeMount (() => {
      count.value++
      console.log('onBeforeMount', count.value)
    })
    onMounted (() => {
      count.value++
      console.log('onMounted', count.value)
    })
    // 注意,onBeforeUpdate 和 onUpdated 里面不要修改值,会死循环的哦!
    onBeforeUpdate (() => {
      console.log('onBeforeUpdate', count.value)
    })
    onUpdated (() => {
      console.log('onUpdated', count.value)
    })
    onBeforeUnmount (() => {
      count.value++
      console.log('onBeforeUnmount', count.value)
    })
    onUnmounted (() => {
      count.value++
      console.log('onUnmounted', count.value)
    })
    // 定义一个函数,修改 count 的值。
    const countAdd = () => {
      count.value++
    }
    return {
      count,
      countAdd
    }
  }
}
</script>

首先,在 vue 3.0 中,生命周期是从 vue 中导出的,我们需要用到哪些,就导出哪些。

可能不少看官会认为多次一举,但实则不然。vue 提供这么多的生命周期,有几个是我们常用的?在大多数的组件中,我们用不到生命周期。即便是页面级别的应用,可能用到最多的是 onMounted 即可。

当然,那些绑定时间的操作会用到解绑,因此会用到 onUnmounted。其它的生命周期,正常情况下是基本用不到的。所以,通过引入使用的这种设定,可以减少我们的最终编译的项目的体积。而且,这样的引入使用,更加的逻辑清晰。

其次,除 setup 之外,其他的生命周期函数,都是在 setup 里面直接书写函数即可。
 

④计算属性

computed.vue

<template>
  <router-link to="/">点这里去首页</router-link>
  <hr>
  <div class="home">
    这里是一个计数器 >>> <span class="red">{{count}}</span> <br>
    右边的数字是上面的数字的十倍 >>> <span class="red">{{bigCount}}</span> <br>
    右边的数字是上面的数字的一百倍 >>> <span class="red">{{computeCount['100x']}}</span> <br>
    右边的数字是上面的数字的一千倍 >>> <span class="red">{{computeCount['1000x']}}</span> <br>
    <button @click="countAdd">点这个按钮上面的数字会变</button>
  </div>
</template>

<script>
// 需要使用计算属性,也需要从 vue 中导出引入
import { ref, computed } from 'vue'
// 导出依然是个对象,不过对象中只有一个 setup 函数
export default {
  setup () {
    // 定义一个 count 的响应式数据,并赋值为 0
    const count = ref(0)
    // 定义一个函数,修改 count 的值。
    const countAdd = () => {
      count.value++
    }
    // 计算属性,使用计算函数并命名,然后在 return 中导出即可
    const bigCount = computed(() => {
      return count.value * 10
    })
    // 计算多个属性,可以通过返回一个对象的方式来实现
    const computeCount = computed(() => {
      return {
        '100x': count.value * 100,
        '1000x': count.value * 1000,
      }
    })
    // 导出一些内容给上面的模板区域使用
    return {
      count,
      countAdd,
      bigCount,
      computeCount
    }
  }
}
</script>

计算属性和生命周期一样,都是从 vue 中导出引入的。我们把计算属性当成一个函数来使用,直接 return 计算结果即可。

暂时先写到这里~

 

 

 

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值