快速入门Vue3(上)

简介: 快速入门Vue3(上)

最近看了小满的vue3教学视频,官方文档,还有小余同学的笔记

也输出一份自己的总结,方便复习回顾。


Vue3的基本语法



Vue3新特性


1. API 风格


Vue2 是选项API(Options API),一个逻辑会散乱在文件不同位置(data、props、computed、watch、生命周期钩子等),导致代码的可读性变差。当需要修改某个逻辑时,需要上下来回跳转文件位置。


Vue3 组合式API(Composition API)则很好地解决了这个问题,可将同一逻辑的内容写到一起,增强了代码的可读性、内聚性,其还提供了较为完美的逻辑复用性方案。


Options API


使用选项式 API,我们可以用包含多个选项的对象来描述组件的逻辑,例如 datamethodsmounted。选项所定义的属性都会暴露在函数内部的 this 上,它会指向当前的组件实例。


<script>
export default {
  // data() 返回的属性将会成为响应式的状态
  // 并且暴露在 `this` 上
  data() {
    return {
      count: 0
    }
  },
  // methods 是一些用来更改状态与触发更新的函数
  // 它们可以在模板中作为事件监听器绑定
  methods: {
    increment() {
      this.count++
    }
  },
  // 生命周期钩子会在组件生命周期的各个不同阶段被调用
  // 例如这个函数就会在组件挂载完成后被调用
  mounted() {
    console.log(`The initial count is ${this.count}.`)
  }
}
</script>
<template>
  <button @click="increment">Count is: {{ count }}</button>
</template>


疑问1:为什么@click里面的increment不需要this.increment呢?methods里面的属性不是会暴露到实例上面吗,刚刚试了,@click="this.increment"

组合式 API (Composition API)


在单文件组件中,组合式 API 通常会与 <script setup> 搭配使用。这个 setup attribute 是一个标识,告诉 Vue 需要在编译时进行一些处理,让我们可以更简洁地使用组合式 API。

<script setup>
import { ref, onMounted } from 'vue'
// 响应式状态
const count = ref(0)
// 用来修改状态、触发更新的函数
function increment() {
  count.value++
}
// 生命周期钩子
onMounted(() => {
  console.log(`The initial count is ${count.value}.`)
})
</script>
<template>
  <button @click="increment">Count is: {{ count }}</button>
</template>


使用ref包裹之后会变成响应式的数据,我们之后也会介绍


2. 重写双向绑定

3. Vue3优化dom

4 .Vue3 Fragment

5. Vue3 Tree shaking


项目搭建


nvm

nvm安装


我们可以通过nvm来管理我们的node版本,方便切换不同的node版本 但是nvm有些坑,总结如下:

  1. nvm 路径不能有空格和中文
  2. 如果你已经有Node版本了,你需要把当前版本收录进去,或者直接卸载掉,用nvm重新安装一遍
  3. 用1.1.7版本,不要用1.1.9最新版本
  4. install版本失败,有可能需要给权限,cmd右键管理员启动即可


感谢b站的这位同学

image.png


nvm命令


# 查看已经安装的node版本
nvm list 
# 查看所有的node版本
nvm list available
# 安装node
nvm install 16.3.2(版本号)
# 切换node版本
nvm use 12.17.0


使用vite构建


npm init vue@latest

image.png


使用vue脚手架工具构建


使用vue脚手架会自动内置了vue-router, pinia,更适合vue的开发


npm init vue@latest

image.png


模板语法


文本插值


在script 声明一个变量可以直接在template 使用用法为 {{ 变量名称 }}


<template>
  <div class="about">
    <h1>{{ message }}</h1>
  </div>
</template>
<script setup lang="ts">
const message = "文本插值语法";
</script>

模板语法是可以编写条件运算的


<template>
  <div class="about">
    <h1>{{ message.length > 5 ? "一高" : "一快" }}</h1>
  </div>
</template>
<script setup lang="ts">
const message = "文本插值语法";
</script>


运算符也是可以支持的

<template>
  <div class="about">
    <h1>{{  message + "运算符" }}}</h1>
  </div>
</template>
<script setup lang="ts">
const message = "文本插值语法";
</script>


操作API 也是支持的


<template>
  <div class="about">
    <h1>{{ message.split("").reverse() }}</h1>
  </div>
</template>
<script setup lang="ts">
const message = "文本插值语法";
</script>


Attribute 绑定


任何 Vue 指令 (以 v- 开头的特殊 attribute) attribute 的值中

v-text


<span v-text="msg"></span>
<!-- 等同于 -->
<span>{{msg}}</span>

v-text 通过设置元素的 textContent 属性来工作,因此它将覆盖元素中所有现有的内容。同时设置v-text和标签中的内容会报错


<template>
  <div v-text="message">同时使用会报错</div>
</template>
<script setup lang="ts">
const message = "v-text用法";
</script>


v-html


<template>
  <div v-html="message"></div>
</template>
<script setup lang="ts">
const message = "<div>innnerHtml</div>";
</script>

v-if


v-if后面的值为真时,才会渲染,当条件改变时会触发过渡效果。

v-if

v-else-if

v-else


v-show


v-show 通过设置内联样式的 display CSS 属性来工作,当元素可见时将使用初始 display 值。当条件改变时,也会触发过渡效果。但是v-if会把整个节点变成一个注释节点,v-show的性能会更好一点


<template>
  <div v-show="bol">v-show为true显示</div>
</template>
<script setup lang="ts">
const bol = true;
</script>

v-on


v-on:可以简写为@

当用于普通元素,只能监听原生DOM事件。当用于自定义元素组件,则监听子组件触发的自定义事件


<!-- 方法处理函数 -->
<button v-on:click="doThis"></button>
<!-- 动态事件 -->
<button v-on:[event]="doThis"></button>
<!-- 内联声明 -->
// $event是一个event对象
<button v-on:click="doThat('hello', $event)"></button>
<!-- 缩写 -->
<button @click="doThis"></button>
<!-- 使用缩写的动态事件 -->
<button @[event]="doThis"></button>
<!-- 停止传播 -->
<button @click.stop="doThis"></button>
<!-- 阻止默认事件 -->
<button @click.prevent="doThis"></button>
<!-- 不带表达式地阻止默认事件 -->
<form @submit.prevent></form>
<!-- 链式调用修饰符 -->
<button @click.stop.prevent="doThis"></button>
<!-- 按键用于 keyAlias 修饰符-->
<input @keyup.enter="onEnter" />
<!-- 点击事件将最多触发一次 -->
<button v-on:click.once="doThis"></button>
<!-- 对象语法 -->
<button v-on="{ mousedown: doThis, mouseup: doThat }"></button>

v-bind


动态的绑定一个或多个 attribute,也可以是组件的 prop。

缩写::


<!-- 绑定 attribute --> 
<img v-bind:src="imageSrc" />
<!-- 内联字符串拼接 -->
<img :src="'/path/to/images/' + fileName" />

v-model


在表单输入元素或组件上创建双向绑定。期望的绑定值类型:根据表单输入元素或组件输出的值而变化

  • 仅限:
  • <input>
  • <select>
  • <textarea>
  • components

v-for


<template>
  <div v-for="item in arr">{{ item }}</div>
</template>
<script setup lang="ts">

v-once


仅渲染元素的组件一次,并跳过之后的更新


<template>
  <button @click="increase"></button>
  <div>{{ val.count }}</div>
</template>
<script setup lang="ts">
import { ref } from "@vue/reactivity";
const val = ref({ count: 2 });
const increase = () => {
  console.log('你更新呀');
  val.value.count++;
};
</script>

当我们点击的时候,数值可以正常的更新,但是加了v-once之后,仅渲染元素和组件一次,并跳过之后的更新。再点击更新count的值元素不会进行更新


<template>
  <button @click="increase"></button>
  <div v-once>{{ val.count }}</div>
</template>
<script setup lang="ts">
import { ref } from "@vue/reactivity";
const val = ref({ count: 2 });
const increase = () => {
  console.log('你更新呀');
  val.value.count++;
};
</script>

v-memo


直接看小满的v-memo


ref全家桶


ref

Vue 提供了一个 ref() 方法来允许我们创建可以使用任何值类型的响应式 ref

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


const count = ref(0)
console.log(count) // { value: 0 }
console.log(count.value) // 0
count.value++
console.log(count.value) // 1

如果ref是一个文本插值(即一个{{ }}符号)计算的最终值,它也被将解包,不需要再.value上取值:


{{ object.foo }}
{{ object.foo.value }}


ref 被传递给函数或是从一般对象上被解构时,不会丢失响应性:

好像自动解包哪些官方文档还没有看明白


ifRef


判断是不是一个ref对象


import { ref, Ref,isRef } from 'vue'
let message: Ref<string | number> = ref("我是message")
let notRef:number = 123
const changeMsg = () => {
  message.value = "change msg"
  console.log(isRef(message)); //true
  console.log(isRef(notRef)); //false
}


shallowRef


ref() 的浅层作用形式。


const state = shallowRef({ count: 1 })
// 不会触发更改
state.value.count = 2
// 会触发更改
state.value = { count: 2 }

特别注意

  • shallowRef只响应到.value,如果这个.value后面在跟值进行修改,就只能在控制台中看见值改变了,而没办法响应到页面中
  • 也就是创建一个跟踪自身 .value 变化的 ref,但不会使其值也变成响应式的
  • ref不能跟shallowRef一起使用,不然shallowRef会被Ref影响,从而造成视图的更新(失去浅层次响应的作用)


triggerRef()


triggerRef()会强制更新我们收集的依赖


const shallow = shallowRef({
  greet: 'Hello, world'
})
shallow.value.greet = 'Hello, universe'
// 会强制更新
triggerRef(shallow)


customRef()


创建一个自定义的 ref,显式声明对其依赖追踪和更新触发的控制方式。

customRef() 预期接收一个工厂函数作为参数,这个工厂函数接受 tracktrigger 两个函数作为参数,并返回一个带有 getset 方法的对象。

一般来说,track() 应该在 get() 方法中调用,而 trigger() 应该在 set() 中调用。然而事实上,你对何时调用、是否应该调用他们有完全的控制权。


<template>
  <div>customerRef: {{ obj }}</div>
  <button @click="change"></button>
</template>
<script setup lang="ts">
import { customRef, ref } from "vue";
const val = ref({ count: 2 });
const obj = MyRef('customerRef')
function change() {
  obj.value = 'customer 修改了'
}
function MyRef(value) {
  return customRef((tracker, trigger) => {
    return {
      get() {
        // 收集依赖
        tracker();
        // 收集完返回出去
        return value;
      },
      set(newVal) {
        // newVal是收到的新的值
        value = newVal;
        // 触发依赖更新
        trigger();
      },
    };
  });
}
</script>


认识Reactive全家桶


reactive


ref支持所有类型,reactive支持引用类型,Array,Object,Map,Set

ref取值是需要.value的,reactive取值的话不需要.value


reactive 基础用法

import { reactive } from 'vue'
let person = reactive({
   name:"小满"
})
person.name = "大满"

数组异步赋值问题


let person = reactive<number[]>([])
setTimeout(() => {
  person = [1, 2, 3]
  console.log(person);
},1000)

这样赋值页面是不会变化的因为会脱离响应式


解决方法


使用push方法


import { reactive } from 'vue'
let person = reactive<number[]>([])
setTimeout(() => {
  const arr = [1, 2, 3]
  person.push(...arr)
  console.log(person);
},1000)

包裹一层对象


type Person = {
  list?:Array<number>
}
let person = reactive<Person>({
   list:[]
})
setTimeout(() => {
  const arr = [1, 2, 3]
  person.list = arr;
  console.log(person);
},1000)

shallowReactive


只能对浅层的数据 如果是深层的数据只会改变值 不会改变视图,和shallowRef差不多


认识to全家桶


toRef

toRef只能修改响应式对象的值并且视图发生变化,非响应式的值可以修改,但是视图没有变化


<template>
  <div>
    <button @click="change">按钮</button>
    {{ state }}
  </div>
</template>
<script setup lang="ts">
import { reactive, toRef } from "vue";
// 必须加上reactive,才能是响应式,否则toRef没有作用
const obj = reactive({
  foo: 1,
  bar: 1,
});
// bar 转化为响应式对象,相当于解构
const state = toRef(obj, "bar");
const change = () => {
  state.value++;
  console.log(obj, state);
};
</script>


toRefs


可以帮我们批量创建ref对象主要是方便我们解构使用


import { reactive, toRefs } from 'vue'
const obj = reactive({
   foo: 1,
   bar: 1
})
let { foo, bar } = toRefs(obj)
foo.value++
console.log(foo, bar);


toRaw


将响应式对象转化为普通对象toRaw() 可以返回由 reactive()、readonly() 、shallowReactive() 或者 shallowReadonly() 创建的代理对应的原始对象。


computed计算属性


计算属性就是当依赖的属性的值发生变化的时候,才会触发它的更改,如果依赖值不变,使用的是缓存中的值


函数形式


import { computed, reactive, ref } from 'vue'
let price = ref(0)//$0
let m = computed<string>(()=>{
   return `$` + price.value
})
price.value = 500


对象形式


<template>
   <div>{{ mul }}</div>
   <div @click="mul = 100">click</div>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue'
let price = ref<number | string>(1)//$0
let mul = computed({
   get: () => {
      return price.value
   },
   set: (value) => {
      price.value = 'set' + value
   }
})
</script>
<style>
</style>


官方文档案例


<script setup>
import { reactive, computed } from 'vue'
const author = reactive({
  name: 'John Doe',
  books: [
    'Vue 2 - Advanced Guide',
    'Vue 3 - Basic Guide',
    'Vue 4 - The Mystery'
  ]
})
// 一个计算属性 ref
const publishedBooksMessage = computed(() => {
  return author.books.length > 0 ? 'Yes' : 'No'
})
</script>
<template>
  <p>Has published books:</p>
  <span>{{ publishedBooksMessage }}</span>
</template>

不使用计算属性


<p>Has published books:</p>
<span>{{ author.books.length > 0 ? 'Yes' : 'No' }}</span>

如果不使用计算属性的话,需要我们在模板中写很长的一段代码,如果我们在多处地方使用的话,可不希望每个地方都写那么长,所以计算属性的作用就体现出来了

计算属性默认是只读的。当你尝试修改一个计算属性时,你会收到一个运行时警告。只在某些特殊场景中你可能才需要用到“可写”的属性,你可以通过同时提供 getter 和 setter 来创建


目录
相关文章
|
1天前
|
移动开发 前端开发
ruoyi-nbcio-plus基于vue3的flowable为了适配文件上传改造VForm3的代码记录
ruoyi-nbcio-plus基于vue3的flowable为了适配文件上传改造VForm3的代码记录
|
1天前
|
JavaScript 前端开发
vue2升级到vue3的一些使用注意事项记录(四)
vue2升级到vue3的一些使用注意事项记录(四)
|
1天前
|
移动开发 前端开发
ruoyi-nbcio-plus基于vue3的flowable收回任务后重新进行提交表单的处理
ruoyi-nbcio-plus基于vue3的flowable收回任务后重新进行提交表单的处理
|
1天前
|
移动开发 前端开发
ruoyi-nbcio-plus基于vue3的flowable多租户机制
ruoyi-nbcio-plus基于vue3的flowable多租户机制
|
1天前
|
移动开发 前端开发
ruoyi-nbcio-plus基于vue3的flowable的消息中心我的消息的升级修改
ruoyi-nbcio-plus基于vue3的flowable的消息中心我的消息的升级修改
|
1天前
|
JavaScript 前端开发
vue3中使用动态组件
vue3中使用动态组件
|
1天前
|
JavaScript 前端开发 容器
Vue 3 中 <transition-group> 组件报错的非 props 属性传递问题
Vue 3 中 <transition-group> 组件报错的非 props 属性传递问题
12 1
|
1天前
|
移动开发 JavaScript 前端开发
ruoyi-nbcio-plus基于vue3的flowable的自定义业务显示历史信息组件的升级修改
ruoyi-nbcio-plus基于vue3的flowable的自定义业务显示历史信息组件的升级修改
|
1天前
|
移动开发 前端开发
ruoyi-nbcio-plus基于vue3的flowable的支持自定义业务流程处理页面detail.vue的升级修改
ruoyi-nbcio-plus基于vue3的flowable的支持自定义业务流程处理页面detail.vue的升级修改
|
1天前
|
移动开发 前端开发
ruoyi-nbcio-plus基于vue3的flowable的自定义业务撤回申请组件的升级修改
ruoyi-nbcio-plus基于vue3的flowable的自定义业务撤回申请组件的升级修改