VUE3.0学习笔记

vue设计思想:

  • 更加注重模块上的拆分。在2.0中无法单独使用部分模块,需要引入完整的vuejs,vue3中的模块之间耦合度低,模块可以独立使用。
  • vue2中很多方法挂载到了实例中导致没有使用也会被打包(还有很多组件也是一样)。vue3重写API,通过构建工具Tree-Shaking 机制实现按需引入,减少用户打包后的体积。
  • vue3允许自定义渲染器,扩展能力强,不会发生以前的事,改写vue源码改造渲染方式,扩展更方便。
  • vue3使用Monorepo管理项目,将模块拆分到package目录中。

    Monorepo是管理项目代码的一种方式,指在一个项目仓库中管理多个模块/包。(一个仓库可以维护多个模块,方便版本管理和依赖管理,模块之间的引用,调用都很方便)

新特性:

1、双向数据绑定(proxy)

  • 可以直接监听数组的变化
  • 对象深度监听性能更好,无需一层层递归,为每个属性添加代理,性能更好,可监听任何方式的数据改变
  • 可监听新增和删除属性

2、CompositionAPI

 vue2使用的是OptionsApi,OptionsApi的弊端:

  • 编写某部分功能时,代码会分布在data,computed,methods等多个Options Api
  • 对于没有参与复杂功能开发的同事, 在代码较分散的时候, 难以理解其逻辑

Composition Api的优势

  • 将同一个业务逻辑的代码写在一起, 可读性更强
  • 在setup中书写没有this, 避免this指向出现的问题, 开发者不需要关注this指向问题

 3、类型检测

  更好的支持TypeScript

4、碎片化节点 Fragment

  • template元素可以当做不可见的包裹元素,并且在v-if上使用,但是最终template不会被渲染出来
  • 不再限制template只有一个根节点, render函数也可以返回数组
  •  类似于小程序的block, react的`React.Fragments`

5、移出了一些api

  • Vue3从实例中移除了 $on、$off 和 $once 方法, 建议使用第三方库mitt
  • Vue3移除了$children; 建议使用 [$refs](https://v3.cn.vuejs.org/guide/component-template-refs.html#模板引用)
  •  Vue3移除了过滤器filter, 建议用方法调用 (局部方法, 全局方法) 或计算属性来替换
  •  全局变量: `Vue.prototype` 替换为 `app.config.globalProperties`

1、v-model

vue3.0支持多个v-model的绑定

App.vue

复制代码
 1 <template>
 2   {{title}}
 3   {{name}}
 4 
 5   <Input v-model:title="title" v-model:name="name"/>
 6 </template>
 7 
 8 <script>
 9 import Input from "./components/Input"
10 export default {
11   name: 'App',
12   components: {
13     Input,
14   },
15   data() {
16     return {
17       title: "聂丽芳",
18       name: "www"
19     }
20   },
21 }
22 </script>
复制代码

Input.vue

复制代码
 1 <template>
 2   <div class="Input">
 3       <input type="text" @input="first" :value="title">
 4       <input type="text" @input="last" :value="name">
 5   </div>
 6 </template>
 7 <script>
 8 export default {
 9  name: 'Input',
10   props: {
11     title: {
12         default: () => "聂丽芳"
13     },
14     name: {
15         default: () => "前端娱乐圈"
16     }
17   },
18   methods: {
19       first(e) {
20           this.$emit("update:title", e.target.value)
21       },
22       last(e) {
23           this.$emit("update:name", e.target.value)
24       }
25   }
26 }
27 </script>
复制代码

2、Setup

创建组件实例,然后初始化props,紧接着就调用setup函数。 从生命周期的角度来看,它会在beforeCreate之前执行。也就是创建组件先执行setupbeforeCreatecreate

this指向

由于不能在setup函数中使用datamethods,为了避免使用Vue出错,所以把setup函数中this修改为了undefined

函数参数

  • props
  • context

props

接收组件传递过来的所有数据,并且都是响应式的。

复制代码
 1 <template>
 2   <div>聂丽芳</div>
 3 </template>
 4 <script>
 5 export default {
 6   name: 'App',
 7   props: {
 8       title: {
 9           type: String
10       }
11   },
12   setup(props) {
13     console.log(props.title)
14   }
15 }
16 </script>
复制代码

Ps:props数据不能使用解构,否则响应式数据失效

复制代码
 1 <template>
 2   <div>聂丽芳</div>
 3 </template>
 4 <script>
 5 export default {
 6   name: 'App',
 7   props: {
 8       title: {
 9           type: String
10       }
11   },
12   setup({ title }) {
13     console.log(title) // 这里响应式数据将失效
14   }
15 }
16 </script>
复制代码

context

该参数提供一个上下文对象,从原来的2.x中选择性的暴露了一些属性。

  • attrs
  • slots
  • emit
    复制代码
     1 <template>
     2   <div>聂丽芳</div>
     3 </template>
     4 <script>
     5 export default {
     6   name: 'App',
     7   props: {
     8       title: {
     9           type: String
    10       }
    11   },
    12   setup(props, { attrs, slots, emit } ) {
    13     console.log(attrs) 
    14   }
    15 }
    16 </script>
    复制代码

    上面,attrsslots都是内部组件实例上对应项的代理,可以确保在更新后仍然还是最新的值。所以这里可以使用解构语法。

返回值

可以将setup函数返回值渲染到页面上。但前提是,setup返回值必须是一个对象,否则返回其它值则渲染无效。

3、Reactive

该方法接收一个参数{}创建一个响应式对象。跟Vue2.x的Vue.observable一样。如果该参数不是对象的话,也可以渲染到模板上,但不是响应式的数据。

复制代码
 1 <template>
 2   <div class="test">
 3     姓名:  {{ name.value }}
 4     {{ test() }}
 5   </div>
 6 </template>
 7 
 8 <script>
 9 import { reactive } from "vue"
10 export default {
11  name: 'test',
12   data() {
13     return {
14 
15     }
16   },
17   setup() {
18     let name = reactive({value: "聂丽芳"})
19     function test() {
20         name.value = "abc"; // 该方法测试响应式数据,可以看到执行完该方法视图也会发生改变
21     }
22     return {
23         name,
24         test
25     }
26   }
27 }
28 </script>
复制代码

4、Ref

该方法接收一个参数,可以是单个值,也可以是一个对象,并且都是响应式的数据。当传入一个对象时{},内部将调用reactive方法进行转换为响应式数据。返回值里面带有.value属性取值,当使用模板渲染的时候可省去.value

复制代码
 1 <template>
 2   <div class="test">
 3     姓名:  {{ name }}
 4     {{ test() }}
 5   </div>
 6 </template>
 7 
 8 <script>
 9 import { ref } from "vue"
10 export default {
11  name: 'test',
12   data() {
13     return {
14 
15     }
16   },
17   setup() {
18 
19     let name = ref("聂丽芳")
20     function test() {
21         name.value = "abc"; // 只是渲染模板可以省略.value,但是在逻辑中还得写哦
22     }
23     return {
24         name,
25         test
26     }
27   }
28 }
29 </script>
复制代码

5、Computed

该方法可以传入一个函数,默认该函数就是getter,不管getter返回值为一个ref响应式数据还是一个普通变量,数据都是只读不能改变。

复制代码
 1 <script>
 2 import { ref, computed } from "vue"
 3 export default {
 4  name: 'test',
 5  setup() {
 6     let name = ref("蛙人")
 7     let test = computed(() => name.value);
 8     test.value = "123" // 修改无效,只能只读
 9   }
10 }
11 </script>
复制代码

传入一个对象setget函数方法,这样就可以修改啦

复制代码
 1 <script>
 2 import { ref, computed } from "vue"
 3 export default {
 4  name: 'test',
 5  setup() {
 6     let name = ref("聂丽芳")
 7     let test = computed({
 8         get() {
 9             return name.value;
10         },
11         set(val) {
12             return name.value = val;
13         }
14     });
15     test.value = "123" 
16   }
17 }
18 </script>
复制代码

6、Readonly

该方法接收传入一个对象,默认是只读功能,是深层对象只读,不管嵌套多少层的属性都是只读状态。

复制代码
 1 <script>
 2 import { readonly } from "vue"
 3 export default {
 4  name: 'test',
 5   setup() {
 6     let obj = {
 7         name: "聂丽芳",
 8         sex: "male",
 9         prodution: {
10             proName: "音响"
11         }
12     }
13     let only = readonly(obj)
14     only.name = "前端娱乐圈" // 修改无效
15     only.prodution.proName = "欢迎关注" // 修改无效
16     console.log(only) 
17   }
18 }
19 </script>
复制代码

7、WatchEffect

该方法接收一个函数并且立即执行,并当该函数里的变量变更时,重新执行该函数。该方法无法获取到原值,只能是改变之后的值。

如果要监听哪个值,需要在该函数里写出来,否则监听无效。

复制代码
 1 import { ref, watchEffect } from "vue"
 2 export default {
 3  name: 'test',
 4   setup() {
 5     let name = ref("聂丽芳");
 6     let age = ref(23);
 7     watchEffect(() => {
 8         name.value; // 监听name
 9         age.value;  // 监听age
10         
11         console.log(name.value)
12         console.log(age.value)
13     })
14     
15     setTimeout(() => {
16         name.value = "前端娱乐圈"
17     }, 5000)
18 
19     setTimeout(() => {
20         age.value = 18
21     }, 1000)
22   }
23 }
24 </script>
复制代码

取消监听

有时候我们想在触发一定的条件后取消监听。这时可以执行watchEffect的返回值。

复制代码
 1 import { ref, watchEffect } from "vue"
 2 export default {
 3  name: 'test',
 4   setup() {
 5     let name = ref("聂丽芳");
 6     let age = ref(23);
 7     let stop = watchEffect(() => {
 8         name.value; // 监听name
 9         age.value;  // 监听age
10         
11         console.log(name.value)
12         console.log(age.value)
13     })
14     
15     setTimeout(() => {
16         name.value = "前端娱乐圈"
17     }, 5000)
18 
19     setTimeout(() => {
20         age.value = 18;
21         setTimeout(stop, 300)
22     }, 1000)
23   }
24 }
25 </script>
复制代码

更多配置项:副作用刷新时机我们一般使用post

 onTrigger可以帮助我们调试watchEffect

复制代码
import { watchEffect, ref } from 'vue'
let message = ref<string>('')
let message2 = ref<string>('')
 watchEffect((oninvalidate) => {
    //console.log('message', message.value);
    oninvalidate(()=>{
 
    })
    console.log('message2', message2.value);
},{
    flush:"post",
    onTrigger () {
        
    }
})
复制代码

8、Watch

watch等同于Vue2.x中的this.$watchwatch需要监听特定数据,默认情况是懒执行,也就是只有当数据发生变化时才执行第二个参数函数。

对比WatchEffectWatch允许我们

  • 懒执行函数
  • 更明确哪些状态改变触发监听器
  • 可以监听获取到变化前后的值

监听单个值

复制代码
 1 <script>
 2 import { ref, watch } from "vue"
 3 export default {
 4  name: 'test',
 5   setup() {
 6     let name = ref("聂丽芳");
 7 
 8     watch(name, (newVal, oldVal) => {
 9         console.log(newVal, oldVal) // 前端娱乐圈, 聂丽芳
10     })
11 
12     setTimeout(() => {
13         name.value = "前端娱乐圈"
14     }, 1000)
15 
16   }
17 }
18 </script>
复制代码

监听多个值

监听多个值,返回的是一个数组对象。

复制代码
 1 <script>
 2 import { ref, watch } from "vue"
 3 export default {
 4  name: 'test',
 5   setup() {
 6     let name = ref("聂丽芳");
 7     let age = ref(23);
 8 
 9     watch([name, age], (newVal, oldVal) => {
10         console.log(newVal, oldVal) // ["前端娱乐圈", 18], ["聂丽芳", 23]
11     })
12     
13     setTimeout(() => {
14         name.value = "前端娱乐圈"
15         age.value = 18
16     }, 1000)
17 
18   }
19 }
20 </script>
复制代码

 

生命周期系列

在Vue3.X也可以在setup函数下使用生命周期,这些钩子函数写法跟之前的生命周期写法不同。

注意:这些生命周期写法只能在setup函数下使用,在其它地方使用则会报错。

与Vue2.x版本生命周期相对应的组合式Api

  • beforeCreate --> setup
  • created --> setup
  • beforeMount --> onBeforeMount
  • mounted --> onMounted
  • beforeUpdate --> onBeforeUpdate
  • updated --> onUpdated
  • beforeDestroy --> onBeforeUnmount
  • destroyed --> onUnmount

 `setup` 是围绕 `beforeCreate` 和 `created` 生命周期钩子运行的,所以不需要显式地定义它们。换句话说,在这些钩子中编写的任何代码都应该直接在 `setup` 函数中编写

Provide && Inject

该方法和Vue2.x的 provideinject一样的。但是Vue3新特性这俩方法只能在setup中使用。

  • Provide:接收2个参数,第一个key值,第二个value值,进行传递
  • Inject:接收2个参数,第一个是providekey值,默认第二个参数可选,可以设置默认值(当找不到key值,设置一个默认值)

App.vue

复制代码
 1 <script>
 2 import test from "./components/test"
 3 import { provide, ref } from "vue"
 4 export default {
 5   name: 'App',
 6   components: {
 7     test
 8   },
 9   setup() {
10     let name = ref("聂丽芳")
11     provide("name", name) // 传入一个响应式数据
12   },
13 }
14 </script>
复制代码

test.vue

复制代码
 1 <template>
 2     {{ NAME }}    
 3 </template>
 4 <script>
 5 import { inject } from "vue"
 6 export default {
 7  name: 'test',
 8   setup() {
 9     let NAME = inject("name")
10     console.log(NAME) // 蛙人
11       
12     let title = inject("key", 123)
13     console.log(title) // 这时就会触发默认值,因为这里找不到这个key值
14       
15     return {
16         NAME
17     }
18   }
19 }
20 </script>
复制代码

移除过滤器filters

在Vue3.x中移除过滤器,不再支持。建议使用computed去替代

不再限制Template一个根节点

Vue3.x中将不在限制模板中只有一个根节点,根组件可以任意多个元素。

<template>
    <div>首页</div>
    <div>新闻</div>
</template>

废弃on,off,once实例方法

Vue3.x中 $on$off 和 $once 实例方法已被移除,应用实例不再实现事件触发接口。

 

Teleport 是什么呢?

Teleport 就像是哆啦 A 梦中的「任意门」,任意门的作用就是可以将人瞬间传送到另一个地方。有了这个认识,我们再来看一下为什么需要用到 Teleport 的特性呢,看一个小例子: 在子组件Header中使用到Dialog组件,我们实际开发中经常会在类似的情形下使用到 Dialog ,此时Dialog就被渲染到一层层子组件内部,处理嵌套组件的定位、z-index和样式都变得困难。 Dialog从用户感知的层面,应该是一个独立的组件,从 dom 结构应该完全剥离 Vue 顶层组件挂载的 DOM;同时还可以使用到 Vue 组件内的状态(data或者props)的值。简单来说就是,即希望继续在组件内部使用Dialog, 又希望渲染的 DOM 结构不嵌套在组件的 DOM 中。 此时就需要 Teleport 上场,我们可以用<Teleport>包裹Dialog, 此时就建立了一个传送门,可以将Dialog渲染的内容传送到任何指定的地方。 接下来就举个小例子,看看 Teleport 的使用方式
我们希望 Dialog 渲染的 dom 和顶层组件是兄弟节点关系, 在index.html文件中定义一个供挂载的元素:
<body>
  <div id="app"></div>
  <div id="dialog"></div>
</body>

定义一个Dialog组件Dialog.vue, 留意 to 属性, 与上面的id选择器一致:

复制代码
<template>
  <teleport to="#dialog">
    <div class="dialog">
      <div class="dialog_wrapper">
        <div class="dialog_header" v-if="title">
          <slot name="header">
            <span>{{ title }}</span>
          </slot>
        </div>
      </div>
      <div class="dialog_content">
        <slot></slot>
      </div>
      <div class="dialog_footer">
        <slot name="footer"></slot>
      </div>
    </div>
  </teleport>
</template>
复制代码

最后在一个子组件Header.vue中使用Dialog组件, 这里主要演示 Teleport 的使用,不相关的代码就省略了。header组件

<div class="header">
    ...
    <navbar />
    <Dialog v-if="dialogVisible"></Dialog>
</div>

suspense

Suspense 只是一个带插槽的组件,只是它的插槽指定了default 和 fallback 两种状态。

Suspense是 Vue3.x 中新增的特性, 那它有什么用呢?别急,我们通过 Vue2.x 中的一些场景来认识它的作用。 Vue2.x 中应该经常遇到这样的场景:

复制代码
<template>
<div>
    <div v-if="!loading">
        ...
    </div>
    <div v-if="loading">
        加载中...
    </div>
</div>
</template>
复制代码
在前后端交互获取数据时, 是一个异步过程,一般我们都会提供一个加载中的动画,当数据返回时配合v-if来控制数据显示。 如果你使用过vue-async-manager这个插件来完成上面的需求, 你对Suspense可能不会陌生,Vue3.x 感觉就是参考了vue-async-manager. Vue3.x 新出的内置组件Suspense, 它提供两个template slot, 刚开始会渲染一个 fallback 状态下的内容, 直到到达某个条件后才会渲染 default 状态的正式内容, 通过使用Suspense组件进行展示异步渲染就更加的简单。:::warning 如果使用 Suspense, 要返回一个 promise :::Suspense 组件的使用:
复制代码
  <Suspense>
        <template #default>
            <async-component></async-component>
        </template>
        <template #fallback>
            <div>
                Loading...
            </div>
        </template>
  </Suspense>
复制代码

asyncComponent.vue:

复制代码
<template>
<div>
    <h4>这个是一个异步加载数据</h4>
    <p>用户名:{{user.nickname}}</p>
    <p>年龄:{{user.age}}</p>
</div>
</template>

<script>
import { defineComponent } from "vue"
import axios from "axios"
export default defineComponent({
    setup(){
        const rawData = await axios.get("http://xxx.xinp.cn/user")
        return {
            user: rawData.data
        }
    }
})
</script>
复制代码

 Composition  Api

1、setup函数

参数1: `props`

在setup中获取props不能使用this; 只能通过该参数进行访问
因为 `props` 是响应式的,不能使用 ES6 解构,它会消除 prop 的响应性。
 如果要使用解构, 可以使用toRefs完成

const { title } = toRefs(props)

参数2: context
 包含属性: attrs, slots, emit, expose
 attrs: 所以非props的attribute
 slots: 父组件传入的插槽
 emit: 子组件emit触发事件, 因为setup中不能使用this.$emit, 所以只能使用该属性
 expose: 暴露公共 property (函数)

2、返回值

 setup的返回值可以在模板template中被使用;
 通过setup的返回值来替代data选项;
通过**返回一个执行函数**来代替在methods中定义的方法

3、关于this

在 `setup()` 内部,`this` 不是该活跃实例的引用, 因为 `setup()` 是在解析其它组件选项之前被调用的,所以 `setup()` 内部的 `this` 的行为与其它选项中的 `this` 完全不同

4、使用refs

复制代码
import { ref } from 'vue'
  export default {
    setup(){
      const titleRef = ref(null)
      return {
        titleRef
      }
    }
  }
复制代码

5、单文件组件 `<script setup>`

setup顶层编写方式,**vue3.2.2**已经变成正式特性

1、优势:

  • 更少的样板内容,更简洁的代码。
  • 能够使用纯 Typescript 声明 props 和抛出事件。
  • 更好的运行时性能 (其模板会被编译成与其同一作用域的渲染函数,没有任何的中间代理)。
  • 更好的 IDE 类型推断性能 (减少语言服务器从代码中抽离类型的工作)。

2、顶层的绑定会被暴露给模板

任何在 `<script setup>` 声明的顶层的绑定 (包括变量,函数声明,以及 import 引入的内容等) 都能在模板中直接使用

3、在 `<script setup>` 中必须使用 `defineProps` 和 `defineEmits` API 来声明 `props` 和 `emits` 

复制代码
  import { defineProps, defineEmits } from 'vue';
  const props = defineProps({
    message: {
      type: String,
      default: "Hello"
    }
  })

  const emit = defineEmits(["increment", "decrement"]);

  const emitEvent = () => {
    emit('increment', "100000")
  }
复制代码

 

 

 

posted @   聂丽芳  阅读(421)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示