Vue3 小结 | 青训营笔记

77 阅读2分钟

这是我参与「第五届青训营」笔记创作活动的第15天。今天记录vue3的相关知识。

一、本堂课重点内容:

Vue3基础知识。

二、详细知识点介绍:

构建 vite 项目

  1. 使用vite初始化一个项目(npm、yarn)
npm init vite@latest
yarn create vite
  1. y继续,然后给项目起个名字,这里我的名字是vite-app
  2. 注意:在哪里打开终端,你的项目就建立在哪里

image-20221001030134810

安装依赖:npm install
依赖安装好了之后就会放到node_modules这个文件夹下
启动项目:npm run dev

第二天之后启动项目可能会报错,说你没有权限

解决方法在下方链接里:

blog.csdn.net/weixin_3786…

package json 命令解析

{
  "scripts": {
    "dev": "vite", // 启动开发服务器,别名:`vite dev``vite serve`
    "build": "vite build", // 为生产环境构建产物
    "preview": "vite preview" // 本地预览生产构建产物
  }
}

安装Vue cli脚手架

安装:npm install @vue/cli -g
检查安装:Vue -V

image-20221001031307642

image-20221001031601936

使用脚手架

vue create project(命令行)

上面二选一就行了,个人认为vite好用

Vite 目录

public 下面的不会被编译 可以存放静态资源

assets 下面可以存放可编译的静态资源

components 下面用来存放我们的组件

App.vue 是全局组件

main ts 全局的 ts 文件

index.html 非常重要的入口文件 (webpack,rollup 他们的入口文件都是 enrty input 是一个 js 文件 而 Vite 的入口文件是一个 html 文件,他刚开始不会编译这些 js 文件 只有当你用到的时候 如 script src="xxxxx.js" 会发起一个请求被 vite 拦截这时候才会解析 js 文件)

vite config ts 这是 vite 的配置文件具体配置项

VsCode Vue3 插件推荐 Vue Language Features (Volar)

SFC 语法规范

*.vue` 件都由三种类型的顶层语法块所组成:`<template>`、`<script>`、`<style>

<template>

  • 每个 *.vue 文件最多可同时包含一个顶层 <template> 块。
  • 其中的内容会被提取出来并传递给 @vue/compiler-dom,预编译为 JavaScript 的渲染函数,并附属到导出的组件上作为其 render 选项。

<script>

  • 每一个 *.vue 文件可以有多个 <script>
  • 该脚本将作为 ES Module 来执行。
  • 默认导出的内容应该是 Vue 组件选项对象,它要么是一个普通的对象,要么是 defineComponent 的返回值。

<script setup>

  • 每个 *.vue 文件最多只能有一个 <script setup> 块 (不包括常规的 <script>)
  • 该脚本会被预处理并作为组件的 setup() 函数使用,也就是说它会在每个组件实例中执行。<script setup> 的顶层绑定会自动暴露给模板。更多详情请查看 文档

<style>

  • 一个 *.vue 文件可以包含多个 <style> 标签。
  • <style> 标签可以通过 scopedmodule attribute (更多详情请查看 SFC 样式特性) 将样式封装在当前组件内。多个不同封装模式的 <style> 标签可以在同一个组件中混

NVM 介绍

NVM 全称 node.js version management ,专门针对 node 版本进行管理的工具,通过它可以安装和切换不同版本的 node.js

GitHub地址:github.com/coreybutler…

Nvm 常用命令操作

nvm list查看现在所有安装的 node 版本
nvm list available查看 nodejs 官方的所有版本
nvm install(版本号)下载对应的 node 版本号
nvm use切换 node 版本

nrm 介绍

nrm 是一个 npm 源管理器,允许你快速地在 npm 源间切换。(其实就是镜像,你可以安淘宝镜像啥的)

  1. 安装

    npm install -g nrm
    
  2. npm ls 查看可选源 星号代表当前使用源

  3. nrm use (源)切换源

  4. nrm add (名称)(源)

  5. 测试速度 nrm test npm

认识目录与SFC

public静态文件夹,通常用来存放一些无需编译的东西,比如图片啥的
src.assets可编译,用来放图片的
src.components组件存放的地方
src.App.vue全局组件
src.main.js用来放公共API的
src.index.html入口文件
package.json配置一些命令还有依赖包的地方
tsconfig.json配置文件的,比如严格模式、语法之类的
vite.config.tsvite的配置文件

对App.vue的认识

  • template只能写一个
  • setup也只能写一个(写多了报错)

npm run dev全过程

  • vite启动项在package里面,但是不能直接在终端输入vite,因为我们没有在环境变量中配置过vite这个变量,没办法执行。

  • npm run dev之所以可以是因为他使用了一种软链接的方式,从源码中可以看到当安装后vite地址会被软链接提升到.bin文件夹中。执行的时候程序就先从这里开始找的

  • 这个.bin里有三个关于vite的文件

    vitelinux系统
    vite.cmdwindows系统
    vite.ps1跨平台的,Linux和windows都可以

模板语法 && Vue指令

data()方法返回组件所需要的数据
methods属性定义组件所需要的方法函数
v-ifVue提供的条件渲染功能,指定变量为true则渲染这个元素,否则不渲染
v-model双向绑定,输入框中的文字变化时,会将其变化同步到绑定的变量上。反之亦然
setup组合式API
{{}}插值语法,将当前组件中定义的变量插入指定位置,且默认实现绑定效果
v-once这个指令设置的组件在进行变量插值的时候只会插值一次
v-html指定一个Vue变量数据,通过HTML解析的方式将原始HTML替换到指定的位置标签
v-bind与标签属性绑定起来,比如v-bind:id="",可以直接缩写为:id=" "
对于可以添加参数的指令,参数和指令之间使用冒号分隔
v-on事件绑定指令,v-on可以被@整个替换
v-else必须紧跟在v-if的后面才能被识别到,if的条件不满足则显示渲染else内的内容
v-show与v-if不一样的是渲染逻辑不一样,v-show指令不管条件是真是假,当前元素都会被渲染。v-if如果是假,则不会渲染
v-for将数组中的数据渲染为列表视图,与index配合的话,index的索引值从0开始。第一个参数为遍历的对象中的属性的值,第二个参数为遍历的对象中的属性的名字,第三个参数为遍历的索引

虚拟DOM和VueKeyDiff算法

查看虚拟DOM上面属性的方法

let div = document.createElement('div')
let str = ''
for (const key in div) {
  str += key + ''
}
console.log(str)
  • 这上面的属性是非常多的,所以直接操作DOM非常浪费性能

  • 解决方案就是 我们可以用 JS 的计算性能来换取操作 DOM 所消耗的性能,既然我们逃不掉操作 DOM 这道坎,但是我们可以尽可能少的操作 DOM

    操作JS是非常快的
    

Vue3 源码地址 https://github.com/vuejs/core

diff算法

image-20221001092144329

乱序的对比,为了防止浪费性能,前面对比一下,后面对比一下,能够有效的分辨出是刚开始就不一样了还是最后不一样。最后面往前移,直到遇到不一样了之后在开始进行下一步的排序复用

Ref全家桶 & 源码解析(重写部分)

小工具介绍 => 根据输出提前自定义好的单词可以输出自定义对应的内容(乍一看好像有点像剪切板)

在vue.json中进行设置

{
 "Print to console":{
     "prefix":"自定义单词部分",
     "body":[
         "输出自定义内容"
     ]
 }
}

ref

接受一个内部值并返回一个响应式且可变的 ref 对象。ref 对象仅有一个 .value property,指向该内部值。

不同的声明方法

image-20221001094826076

  • 推荐类型比较复杂的时候方便自定义

image-20221001094922141

  • 或者什么都不要,让编辑器自己推导

image-20221001095054253

这里要响应改变值的话,要记得加.value,因为Proxy是在.value中的

image-20221001095226462

<template>
  <div>{{Man}}</div>
  <button @click="change()">修改</button>
</template><script setup lang="ts">
  import {ref,isRef} from 'vue'
  const Man = ref({name:"小余"})
​
  const change = () =>{
    Man.value.name = 'yupi'
    console.log(Man)
    console.log(isRef(Man))
  }
</script>

isRef

作用:判断一个东西是不是一个ref对象,结果返回布尔值

console.log(isRef(Man))

shallowRef

作用:shallowRef是浅层次的响应,而ref是深层次的响应

shallowRef只响应到.value,如果这个.value后面在跟值进行修改,就只能在控制台中看见值改变了,而没办法响应到页面中

也就是创建一个跟踪自身 .value 变化的 ref,但不会使其值也变成响应式的

注意:ref不能跟shallowRef一起使用,不然shallowRef会被Ref影响,从而造成视图的更新(失去浅层次响应的作用)

<template>
  <div>Ref:{{XiaoYu}}</div>
  <div>shallowRef:{{XiaoYu2}}</div>
  <button @click="change()">修改</button>
</template><script setup lang="ts">
  import {ref,isRef,shallowRef} from 'vue'
  const XiaoYu = ref({name:"小余"})
  const XiaoYu2 = shallowRef({name:"小余2号"})
  const yupi = {name:"鱼皮"}
​
  const change = () =>{
    // XiaoYu.value.name = '小余抓住了一只yupi' 这里必须注销掉,不如ref会影响到shallowRef,导致视图的更新(也就是会造成下方的小余今天摸鱼了也一同刷新)
    XiaoYu2.value.name = '小余今天摸鱼了'
    console.log(XiaoYu)
    console.log("这是小余",isRef(XiaoYu))
    console.log("这是鱼皮",isRef(yupi))
  }
</script>

triggerRef

  • 因为在ref底层更新的逻辑的时候,会调用triggerRef
  • 而triggerRef会强制更新我们这个收集的依赖
  • 强制更新页面 DOM

customRef

  • 让我们自己去自定义一个ref

  • customRef 是个工厂函数要求我们返回一个对象 并且实现 get 和 set 适合去做防抖之类的

  • customRef也是一个浅层的响应

  • 里面返回的是set跟get两个方法,回调里面接收的是两个函数,一个是track,一个是trigger

    • track:收集依赖,收集完return回去
    • 触发依赖交给set,接收一个newVal
    • track 作用:通知 Vue 追踪 value 的变化 (相当于提前和 get 商量一下,让他认为这个 value 有用的!)
    • trigger 作用:通知 Vue 重新解析模板。
<template>
 
  <div>{{obj}}</div>//不用设置ref了,因为我们自己手动实现了一个
  <hr>
  <div>
    {{ name }}
  </div>
  <hr>
  <button @click="change()">修改</button>
 
</template>
 
<script setup lang='ts'>
import { ref, reactive, onMounted, shallowRef, customRef } from 'vue'
 //这下面是customRef的演示,自己定义ref,接近源码的表现
  const change = ()=>{
  function MyRef<T>(value:T){//泛型
    let timer:any
    return customRef((track, trigger)=>{//track:收集依赖的 trigger:触发依赖
      return{
        get(){
          track()
          return value//收集完依赖就返回 回去了
        },
        set(newVal){//这里会收到新的值,调用接口,调用太多次的话,服务器的压力就会很大,这个时候我们就可以自己设置一个防抖节流
          clearTimeout(timer)//清除定时器,不让他同时存在多个定时器(同一时间只能有一个定时器)
          timer = setTimeout(()=>{
            console.log("吃午饭了")
            value = newVal//将新值赋给value
            timer = null//清空一下时间
            trigger()
          },500)//时间间隔设置为0.5秒,防抖节流
        }
      }
    })
  }
 
 
const obj = MyRef<string>('customRef小余')
 
 
  const change = ()=>{
    obj.value = "customRef被修改了,到饭点准备干饭了"
  }
 
</script>
<style scoped>
</style>
ref小技巧
  1. image-20221001111117720打开这个能够让我们观察value方便一点,控制台点一下就行,少点一下。就是格式化了,e f系列跟reactive系列都可以使用
  2. ref是可以获取DOM元素的,在html部分中ref="xxx",这个xxx要与在JavaScript里面声明的变量名一样,比如const xxx = ref<泛型>(),然后console控制台输出一下,ref.value.innerText就能够获取到了

三、实践练习例子:

例子已经在文章中举出。

四、课后个人总结:

本章的知识点需要大量的实例和参考资料来辅助理解。

五、引用参考:

我主要是基于老师讲解提供的代码仓库进行理解和分析,并记录了自己的心得。