vue3总结

# vue3性能提升

  • 打包大小减少41%
  • 初次渲染快55%,更新渲染快133%
  • 内存减少54%

# 源码升级

  • 用proxy代替defineProperty实现响应式
  • 重写虚拟DOM实现
  • 引入tree shaking

# 拥抱TS

  • vue3支持TypeScript语言

# 其他一些列新特征

# 使用vue/cli创建web项目(需要vue/cli4.5.0以上的版本)

  • 配置淘宝镜像:npm config set registry https://registry.npm.taobao.org
  • 安装vue/cli:npm install -g @vue/cli
  • 切换到你要创建项目的目录,然后使用命令创建项目:vue create xxx
  • 启动项目:npm install serve
Vue CLI v5.0.8
? Please pick a preset: (Use arrow keys)   
> Default ([Vue 3] babel, eslint)
  Default ([Vue 2] babel, eslint)
  Manually select features
1
2
3
4
5
E:\BaiduSyncdisk\validation\javascript>vue create vue3.x-cli
?  Your connection to the default yarn registry seems to be slow.     
   Use https://registry.npmmirror.com for faster installation? (Y/n) y
1
2
3
Vue CLI v5.0.8
? Please pick a preset: (Use arrow keys)
> Default ([Vue 3] babel, eslint)
  Default ([Vue 2] babel, eslint)
  Manually select features
1
2
3
4
5
Vue CLI v5.0.8
? Please pick a preset: Default ([Vue 2] babel, eslint)
? Pick the package manager to use when installing dependencies: (Use arrow keys)
> Use Yarn
  Use NPM
1
2
3
4
5
Vue CLI v5.0.8
✨  Creating project in E:\BaiduSyncdisk\validation\javascript\vue3.x-cli.
⚙️  Installing CLI plugins. This might take a while...

yarn install v1.22.19
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[#####################-------------------------------------------------------] 496/772 
1
2
3
4
5
6
7
8
9
success Saved lockfile.
Done in 11.90s.
⚓  Running completion hooks...

📄  Generating README.md...

🎉  Successfully created project vue3.x-cli.
👉  Get started with the following commands:

 $ cd vue3.x-cli
 $ yarn serve

E:\BaiduSyncdisk\validation\javascript>cd vue3.x-cli

E:\BaiduSyncdisk\validation\javascript\vue3.x-cli>yarn serve
yarn run v1.22.19
$ vue-cli-service serve
 INFO  Starting development server...

 DONE  Compiled successfully in 4278ms 
 
  App running at:
  - Local:   http://localhost:8081/
  - Network: http://192.168.3.82:8081/

  Note that the development build is not optimized.
  To create a production build, run yarn build.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 使用vite构建vue3项目

  • vite无须打包,可以快速冷启动
  • 轻量快速的热重载HMR
  • 真正的按需编译,不再等待整个项目完全编译完成
npm init vite-app vue3-vite
cd vue3-vite
npm install
npm run dev

E:\BaiduSyncdisk\validation\javascript>cd vue3-vite

E:\BaiduSyncdisk\validation\javascript\vue3-vite>npm install
npm WARN deprecated sourcemap-codec@1.4.8: Please use @jridgewell/sourcemap-codec instead
npm WARN deprecated rollup-plugin-terser@7.0.2: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser

added 299 packages in 19s

E:\BaiduSyncdisk\validation\javascript\vue3-vite>npm run dev

> vue3-vite@0.0.0 dev
> vite

[vite] Optimizable dependencies detected:
vue

  Dev server running at:
  > Network:  http://192.168.3.82:3000/
  > Local:    http://localhost:3000/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 查看webpack完整配置文件

为了免于破坏,vue脚手架把webpack配置文件webpack.config.js隐藏了,想查看完整配置文件需执行 vue inspect > output.js命令。

# webpack中用于语法检查的loader

  • eslint
  • jslint
  • jshint

# 自动升级过期包

  • 第一步:使用npm 命令查看已过期安装包 npm outdated
  • 第二步:安装升级插件 npm install -g npm-check-updates
  • 第三步:查看最新版本命令 ncu
  • 第四步:升级低版本npm包文件 ncu -u

# 查看包所有版本号

npm view element-plus versions

# 常用插件

  • uuid 自动生成id插件
  • nanoid 自动生成id插件
  • pubsub-js 消息发布订阅插件
  • axios 异步请求插件 (其他工具:xhr 发ajax请求鼻祖,jquery,fetch 原生工具)

# 常用技术

# 自定义事件

说明:Student 和 School 都是vue组件

自定义事件注册和触发遵循的一条规则是,事件的注册和触发需要是同一个对象

  • 写法一
<Student v-on:studentEvent="getStudentName"></Student>
methods: {
    // ...params包裹了给方法传递的除name外的剩余全部参数
    getStudentName(name, ...params) {
      console.log("通过事件获取到的姓名:" + name);
    },
}
1
2
3
4
5
6
7
  • 写法二
<Student @studentEvent="getStudentName"></Student>
methods: {
    // ...params包裹了给方法传递的除name外的剩余全部参数
    getStudentName(name, ...params) {
      console.log("通过事件获取到的姓名:" + name);
    },
}
1
2
3
4
5
6
7
  • 写法三
在一个地方注册事件,并回调函数
<Student ref="student"></Student>
mounted() {
    setTimeout(() => {
      this.$refs.student.$on("studentEvent", this.getStudentName);
    }, 3000);
},
methods: {
    getStudentName(name, ...params) {
      console.log("通过事件获取到的姓名:" + name);
    },
},

在另一个地方触发事件并传递数据
<button @click="sendStudentName">把学生的姓名给app</button>
methods: {
    sendStudentName() {
      this.$emit("studentEvent", this.name,参数二,参数三);
    },
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
这种写法相当于给组件自身上绑定一个原生点击事件,这样会把click事件交给Student组件最外层的div来执行
<Student ref="student" @click.native="show"></Student>
show(){
    console.log('执行了一个原生dom事件')
}

如果这样写就会被当做一个自定义事件,需要通过emit来触发
<Student ref="student" @click="show"></Student>
show(){
    console.log('执行了一个原生dom事件')
}
this.$emit("click");
1
2
3
4
5
6
7
8
9
10
11
12
解绑事件一个事件或者多个事件
beforeDestroy() {
    // 解绑一个事件直接在对象上指定
    this.$refs.student.$off("studentEvent", this.getStudentName);

    // 解绑多个事件直接在vm上删除多个事件对象
    // this.$off(['studentEvent1','studentEvent2'])
},

组件销毁时,其身上绑定的事件也将自动失效
methods: {
    destroyStudent() {
      this.$destroy();
    },
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# http请求跨域

举个发送请求的栗子

请求端 http:localhost:8080 服务端 http:localhost:5000

解释跨域本质:浏览器发送的请求确实将请求发送到服务器上了,服务器也收到了本次的请求,服务器也把数据交给了浏览器,但是浏览器没有进一步给到用户页面(因为浏览器发现跨域请求了,所以将数据握在手里不给页面了)

解决跨域问题: 1.标准解决方式:cors,不用浏览器做任何事情,但需要服务端人员返回数据时带上必要的特殊相应头。但是有个问题就是任何人都可以找这台服务器要数据了。 2.jsonp解决方式:前后端都需要写东西才能解决。只能解决get请求方式。 3.代理服务器解决方式:代理服务的端口和浏览器访问的端口是一致的。 代理服务器开启的方式有:1.经典方式nginx 2.vue-cli

配置代理服务器,5000是存储数据的服务器端口号 //代理方式二:配置多个代理 devServer: { proxy: { // '/xxx' 请求前缀,目的是为了判断请求是否要走代理,增加了请求的灵活性 '/atguigu': { // 访问的真实数据服务器地址和端口 target: 'http://localhost:5000', // 配置路径,目的匹配服务器接口路径 pathRewrite: { "^/atguigu": "" }, // 支持websocket,默认true ws: true, // 指出请求的来源地址,true就实话实说,false就虚报地址,默认true changeOrigin: true, // 控制请求头中host值,设置成false比较好 }, '/demo': { // 访问的真实数据服务器地址和端口 target: 'http://localhost:5001', // 配置路径,目的匹配服务器接口路径 pathRewrite: { "^/demo": "" }, // 支持websocket,默认true ws: true, // 指出请求的来源地址,true就实话实说,false就虚报地址,默认true changeOrigin: true, // 控制请求头中host值,设置成false比较好 }, } }

注意:并不是所有的请求都通过代理服务器发送给5000。当8080服务器有的东西就不需要通过代理。

# 关键技术点

大总管
import { createApp } from 'vue'

const app = createApp({
  data() {
    return {
      count: 0
    }
  }
})

app.config.errorHandler = (err) => {
//定义一个应用级的错误处理器,用来捕获所有子组件上的错误。
}

app.config.warnHandler = (msg, instance, trace) => {
  // `trace` 是组件层级结构的追踪,警告仅会在开发阶段显示,因此在生产环境中,这条配置将被忽略
}

app.config.performance //设置此项为 true 可以在浏览器开发工具的“性能/时间线”页中启用对组件初始化、编译、渲染和修补的性能表现追踪。仅在开发模式和支持 performance.mark API 的浏览器中工作。

app.component('TodoDeleteButton', TodoDeleteButton)//这使得 TodoDeleteButton 在应用的任何地方都是可用的。

app.mount('#app')//确保在挂载应用实例之前完成所有应用配置!//或者
app.mount(document.body.firstChild)//也可以将app挂在到实际的dom中。

app.unmount()//卸载一个已挂载的应用实例。卸载一个应用会触发该应用组件树内所有组件的卸载生命周期钩子。

app.use()//安装一个插件。1.插件可以是一个带 install() 方法的对象,亦或直接是一个将被用作 install() 方法的函数。2.插件选项 (app.use() 的第二个参数) 将会传递给插件的 install() 方法。3.若 app.use() 对同一个插件多次调用,该插件只会被安装一次。

app.mixin()//vue3不推荐使用,勉强能用完全是为了兼容性。

app.version//提供当前应用所使用的 Vue 版本号。这在插件中很有用,因为可能需要根据不同的 Vue 版本执行不同的逻辑。

setup()//setup() 钩子是在组件中使用组合式 API 的入口,通常只在以下情况下使用:1.需要在非单文件组件中使用组合式 API 时。2.需要在基于选项式 API 的组件中集成基于组合式 API 的代码时。对于结合单文件组件使用的组合式 API,推荐通过 <script setup> 以获得更加简洁及符合人体工程学的语法。

ref()//接受一个内部值,返回一个响应式的、可更改的 ref 对象,此对象只有一个指向其内部值的属性 .value。

computed()//接受一个 getter 函数,返回一个只读的响应式 ref 对象。该 ref 通过 .value 暴露 getter 函数的返回值。它也可以接受一个带有 get 和 set 函数的对象来创建一个可写的 ref 对象。

reactive()//返回一个对象的响应式代理。

readonly()//接受一个对象 (不论是响应式还是普通的) 或是一个 ref,返回一个原值的只读代理。

isRef()//检查某个值是否为 ref。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
app.component()

如果同时传递一个组件名字符串及其定义,则注册一个全局组件;如果只传递一个名字,则会返回用该名字注册的组件 (如果存在的话)。

app.component()

例如:
import { createApp } from 'vue'

const app = createApp({})

// 注册一个选项对象
app.component('my-component', {
  /* ... */
})

// 得到一个已注册的组件
const MyComponent = app.component('my-component')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
app.directive()

如果同时传递一个名字和一个指令定义,则注册一个全局指令;如果只传递一个名字,则会返回用该名字注册的指令 (如果存在的话)。

app.directive()

例如:
import { createApp } from 'vue'

const app = createApp({
  /* ... */
})

// 注册(对象形式的指令)
app.directive('my-directive', {
  /* 自定义指令钩子 */
})

// 注册(函数形式的指令)
app.directive('my-directive', () => {
  /* ... */
})

// 得到一个已注册的指令
const myDirective = app.directive('my-directive')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
app.provide()

提供一个值,可以在应用中的所有后代组件中注入使用。

app.provide()

import { createApp } from 'vue'
const app = createApp(/* ... */)
app.provide('message', 'hello')

//在某个应用组件中
import { inject } from 'vue'
export default {
  setup() {
    console.log(inject('message')) // 'hello'
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
app.runWithContext()

使用当前应用作为注入上下文执行回调函数。

import { inject } from 'vue'

app.provide('id', 1)

const injected = app.runWithContext(() => {
  return inject('id')
})

console.log(injected) // 1
1
2
3
4
5
6
7
8
9

需要一个回调函数并立即运行该回调。在回调同步调用期间,即使没有当前活动的组件实例,inject() 调用也可以从当前应用提供的值中查找注入。回调的返回值也将被返回。

app.config.globalProperties

一个用于注册能够被应用内所有组件实例访问到的全局属性的对象。

app.config.globalProperties.msg = 'hello'
1

这使得 msg 在应用的任意组件模板上都可用,并且也可以通过任意组件实例的 this 访问到

nextTick()

等待下一次 DOM 更新刷新的工具方法。 当你在 Vue 中更改响应式状态时,最终的 DOM 更新并不是同步生效的,而是由 Vue 将它们缓存在一个队列中,直到下一个“tick”才一起执行。 这样是为了确保每个组件无论发生多少状态改变,都仅执行一次更新。 nextTick() 可以在状态改变后立即使用,以等待 DOM 更新完成。你可以传递一个回调函数作为参数,或者 await 返回的 Promise。

<script setup>
import { ref, nextTick } from 'vue'

const count = ref(0)

async function increment() {
  count.value++

  // DOM 还未更新
  console.log(document.getElementById('counter').textContent) // 0

  await nextTick()
  // DOM 此时已经更新
  console.log(document.getElementById('counter').textContent) // 1
}
</script>

<template>
  <button id="counter" @click="increment">{{ count }}</button>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
setup()

钩子是在组件中使用组合式 API 的入口

export default {
  setup(props, context) {
    // props 是响应式的,并且会在传入新的 props 时同步更新,请注意如果你解构了 props 对象,解构出的变量将会丢失响应性。
    // 该上下文对象context是非响应式的,可以安全地解构  setup(props, { attrs, slots, emit, expose })
    
    // 透传 Attributes(非响应式的对象,等价于 $attrs)
    console.log(context.attrs)

    // 插槽(非响应式的对象,等价于 $slots)
    console.log(context.slots)

    //attrs 和 slots 都是有状态的对象,它们总是会随着组件自身的更新而更新。这意味着你应当避免解构它们,并始终通过 attrs.x 或 slots.x 的形式使用其中的属性。

    // 触发事件(函数,等价于 $emit)
    console.log(context.emit)

    // 暴露公共属性(函数)
    console.log(context.expose)

    // 将 `props` 转为一个其中全是 ref 的对象,然后解构
    const { title } = toRefs(props)
    // `title` 是一个追踪着 `props.title` 的 ref
    console.log(title.value)

    // 或者,将 `props` 的单个属性转为一个 ref
    const title = toRef(props, 'title')

    // 让组件实例处于 “关闭状态”
    // 即不向父组件暴露任何东西
    context.expose()

    const publicCount = ref(0)
    const privateCount = ref(0)
    // 有选择地暴露局部状态
    context.expose({ count: publicCount })
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
上次更新: 2025/02/10, 20:20:37
最近更新
01
vue3尚硅谷课件
04-26
02
Git问题集合
01-29
03
安装 Nginx 服务器
01-25
更多文章>
×
×