当前位置: 首页 > news >正文

vue3 基础笔记

基础模板语法

//1. 普通文本插值: 
<p>{{ rawHtml }}</p>//2. v-html 指令:插入 HTML 内容,并希望 Vue 将其视为 HTML 而不是纯文本
<p v-html="rawHtml"></p>
let rawHtml = '<span>这是一个 <b>HTML</b> 片段</span>'//3.v-bind= 简写成 ':'  //可动态绑定数据(布尔值,对象,单个值ID...)
<p :id="dynamicId">v-bind</p>//可动态绑定参数,事件<a :[attributename]="url">{{ url }}</a><a @[eventname]="doSomething"></a>//4. Vue 实际上在所有的数据绑定中都支持完整的 JS 表达式:
<p>{{ number + 1 }} {{ ok ? 'YES' : 'NO' }}</p>
<p>{{ message.split('').reverse().join('') }}</p>
<p :id="`list-${listId}`">半动态绑定</p>

注意:当使用 DOM 内嵌模板 (直接写在 HTML 文件里的模板) 时,我们需要避免在名称中使用大写字母,因为浏览器会强制将其转换为小写


事件监听

//监听事件:v-on ,缩写@//内联事件处理器:
<button @click="count++">count:{{ count }}</button>//方法事件处理器:
<button @click="addCount()">count:{{ count }}</button>

方法事件处理器接受的第一个参数为DOM的原生事件。有时我们需要在内联事件处理器中访问原生 DOM 事件。可以向该处理器方法传入一个特殊的 $event 变量,或者使用内联箭头函数

<!-- 使用特殊的 $event 变量 -->
<button @click="warn('Form cannot be submitted yet.', $event)">Submit
</button>
<!-- 使用内联箭头函数 -->
<button @click="(event) => warn('Form cannot be submitted yet.', event)">Submit
</button>

class-bind

class绑定并不一定需要写成内联字面量的形式

//1.可以直接绑定一个对象
<div :class="{ active: isActive, 'text-danger': hasError }"></div>//2.也可以绑定一个返回对象的计算属性(这是一个常见且很有用的技巧)
<div :class="classObject2"></div>//3.还可以给绑定一个数组来渲染多个 CSS class//4.:style 支持绑定 JavaScript 对象值,对应的是 HTML 元素的 style 属性<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

ref和reactive

Ref

ref接收参数,并将其包裹在一个带有 .value 属性的ref对象中返回:

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

深层响应性:ref 可以持有任何类型的值,包括深层嵌套的对象、数组或者 JS 内置的数据结构,比如 Map(即使改变嵌套对象或数组时,变化也会被检测到)

也可以通过 shallow ref 来放弃深层响应性。对于浅层 ref,只有 .value 的访问会被追踪。浅层 ref 可以用于避免对大型数据的响应性开销来优化性能、或者有外部库管理其内部状态的情况。

Reactive

与将内部值包装在特殊对象中的 ref 不同,reactive() 将使对象本身具有响应性:

const state = reactive({ stateCount: 0 })
const addCount = () => {state.stateCount++
}const obj4 = {name: 'obj4'
}
const proxy = reactive(obj4)
// reactive() 返回的是一个原始对象的 Proxy,它和原始对象是不相等的:
console.log(proxy == obj4)
// 在同一个对象上调用 reactive() 会返回相同的代理
console.log(reactive(obj4) === proxy)
// 在一个代理上调用 reactive() 会返回它自己
console.log(reactive(proxy) === proxy)
// 注意:ref得不到上述结果

响应式对象是 JS代理,其行为就和普通对象一样。不同的是,Vue 能够拦截对响应式对象所有属性的访问和修改,以便进行依赖追踪和触发更新

reactive()具有一定局限性

1.有限的值类型:它只能用于对象类型 。能持有如原始类型

2.不能替换整个对象:由于 Vue 的响应式跟踪是通过属性访问实现的,因此我们必须始终保持对响应式对象的相同引用

这意味着我们不能轻易地“替换”响应式对象,因为这样的话与第一个引用的响应性连接将丢失:

const state2 = reactive({ count: 0 })// 上面的 ({ count: 0 }) 引用将不再被追踪
// (响应性连接已丢失!)state2 = reactive({ count: 1 })   //state2将报错

 3.对解构操作不友好:当我们将响应式对象的原始类型属性解构为本地变量时,或者将该属性传递给函数时,我们将丢失响应性连接

const state3 = reactive({ count3: 0 })// 当解构时,count 已经与 state.count 断开连接
// let { count3 } = state
// // 不会影响原始的 state3
// count3++
console.log(state3.count3)// 该函数接收到的是一个普通的数字
// 并且无法追踪 state.count 的变化
// 我们必须传入整个对象以保持响应性
// callSomeFunction(state3.count)

computed

computed() 方法期望接收一个 getter 函数,返回值为一个计算属性 ref,也就是说它会自动追踪响应式依赖,任何依赖于计算属性的绑定都会与计算属性同布更新。

计算属性和方的区别-----------缓存性

计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才重新计算。

这意味着只要计算属性的getter数据不变,无论访问多少次计算结果,它都会立即返回先前的计算结果,而不用重复执行 getter 函数。

// 比如:下面的计算属性永远不会更新,因为 Date.now() 并不是一个响应式依赖
const now = computed(() => Date.now())
console.log(now.value)

computed,methods和watch区别

1).用途

computed:计算属性。通常用于处理复杂逻辑或数据转换,如格式化日期、拼接字符串、计算总数等。

methods  :方法。通常用于执行事件处理、数据转换等操作。可以在在模板,computed,watch,声明周期钩子等内部使用。

watch      :监听器。通常用于执行数据验证、调用异步API、执行副作用(如更新DOM、发送网络请求等)以及根据数据变化执行复杂的逻辑。

2).缓存机制 *

computed:有缓存机制。只有当其依赖的响应式数据发生变化时,才会重新计算。反之,无论访问多少次计算结果,它都会立即返回先前的计算结果,而不用重复执行 getter 函数。

methods :无缓存机制。调用一次执行一次代码。

watch      :无缓存机制。

3).异步支持

computed:不支持。计算属性必须同步地返回一个值。

methods  :支持

watch      :支持

4).调用时机

computed:当组件渲染或计算属性被访问时,如果依赖的数据发生变化,则重新计算。

methods  :当被其他逻辑调用时

watch      :当侦听的数据发生变化时,执行回调函数。


表单元素

表单输入绑定 | Vue.js (vuejs.org)


修饰符

修饰符的目的:让方法更加专注于数据逻辑而不去处理DOM事件的细节

事件修饰符

比如事件冒泡和默认行为等,虽然可以直接在方法内部调用 event.preventDefault() 或者 event.stopPropagation(),甚至还比较常见。但用下面这种写法显然更加优雅

.stop .prevent .self .capture .once .passive

按键修饰符

在监听键盘事件时,我们经常需要检查特定的按键。Vue 允许在 v-on 或 @ 监听按键事件时添加按键修饰符。

<!-- 仅在 `key` 为 `Enter` 时调用 `submit` -->
<input @keyup.enter="submit" />

你可以直接使用 KeyboardEvent.key 暴露的按键名称作为修饰符,但需要转为 kebab-case 形式。

<input @keyup.page-down="onPageDown" />
input修饰符

.lazy

默认情况下,v-model 会在每次 input 事件后更新数据。你可以添加 lazy 修饰符来改为在每次 change 事件后更新数据:

<!-- 在 "change" 事件后同步更新而不是 "input" -->
<input v-model.lazy="msg" />

 .number

如果你想让用户输入自动转换为数字,你可以在 v-model 后添加 .number 修饰符来管理输入

<input v-model.number="age" />

如果该值无法被 parseFloat() 处理,那么将返回原始值。

number 修饰符会在输入框有 type="number" 时自动启用。

.trim 

如果你想要默认自动去除用户输入内容中两端的空格,你可以在 v-model 后添加 .trim 修饰符:

<input v-model.trim="msg" />


Teleport

vue的内置组件,和它的名字一样,作用就是“传送”,将Teleport包裹的部分传送到DOM 中的任意位置位置。通常Teleport用于解决某些特定场景下的布局和嵌套问题,如 modal 对话框、弹出框、全局头部等。

为了达成这部分内容,在逻辑上不属于,或从属于该节点,但从整个应用视图的角度来看,它们在外层或者平级与某个节点的目。很复杂:但某些场景会需要,比如事件冒泡,样式隔离,动态目标

<template><div><!-- 正常渲染的按钮 --><button @click="showModal = true">打开模态框</button><!-- Teleport 组件,将模态框内容渲染到 el-card 标签下 --><teleport to=".content"><div v-if="showModal" class="modal"><p>这是一个模态框</p><button @click="showModal = false">关闭</button></div></teleport></div><el-card class="content"> </el-card>
</template><script setup>
import { ref } from 'vue'
const showModal = ref(false)
</script>

禁用 Teleport​

在某些场景下可能需要视情况禁用 <Teleport>。举例来说,我们想要在桌面端将一个组件当做浮层来渲染,但在移动端则当作行内组件。我们可以通过对 <Teleport> 动态地传入一个 disabled prop 来处理这两种不同情况。

<Teleport :disabled="isMobile">...
</Teleport>

这里的 isMobile 状态可以根据 CSS media query 的不同结果动态地更新。

我们也可以将 <Teleport> 和 <Transition> 结合使用来创建一个带动画的模态框。你可以看看这个示例。

核心:<Teleport> 只改变了渲染的 DOM 结构,它不会影响组件间的逻辑关系。也就是说,如果 <Teleport> 包含了一个组件,那么该组件始终和这个使用了 <Teleport> 的组件保持逻辑上的父子关系。传入的 props 和触发的事件也会照常工作。


异步组件基本用法​

在大型项目中,我们可能需要拆分应用为更小的块,并仅在需要时再从服务器加载相关组件。Vue 提供了 defineAsyncComponent 方法来实现此功能:

import { defineAsyncComponent } from 'vue'const AsyncComp = defineAsyncComponent(() => {return new Promise((resolve, reject) => {// ...从服务器获取组件resolve(/* 获取到的组件 */)})
})
// ... 像使用其他一般组件一样使用 `AsyncComp`

如你所见,defineAsyncComponent 方法接收一个返回 Promise 的加载函数。这个 Promise 的 resolve 回调方法应该在从服务器获得组件定义时调用。你也可以调用 reject(reason) 表明加载失败。

ES 模块动态导入也会返回一个 Promise,所以多数情况下我们会将它和 defineAsyncComponent 搭配使用。类似 Vite 和 Webpack 这样的构建工具也支持此语法 (并且会将它们作为打包时的代码分割点),因此我们也可以用它来导入 Vue 单文件组件:

js

import { defineAsyncComponent } from 'vue'const AsyncComp = defineAsyncComponent(() =>import('./components/MyComponent.vue')
)

最后得到的 AsyncComp 是一个外层包装过的组件,仅在页面需要它渲染时才会调用加载内部实际组件的函数。它会将接收到的 props 和插槽传给内部组件,所以你可以使用这个异步的包装组件无缝地替换原始组件,同时实现延迟加载。

与普通组件一样,异步组件可以使用 app.component() 全局注册:

js

app.component('MyComponent', defineAsyncComponent(() =>import('./components/MyComponent.vue')
))

也可以直接在父组件中直接定义它们:

vue

<script setup>
import { defineAsyncComponent } from 'vue'const AdminPage = defineAsyncComponent(() =>import('./components/AdminPageComponent.vue')
)
</script><template><AdminPage />
</template>
加载与错误状态​

异步操作不可避免地会涉及到加载和错误状态,因此 defineAsyncComponent() 也支持在高级选项中处理这些状态:

js

const AsyncComp = defineAsyncComponent({// 加载函数loader: () => import('./Foo.vue'),// 加载异步组件时使用的组件loadingComponent: LoadingComponent,// 展示加载组件前的延迟时间,默认为 200msdelay: 200,// 加载失败后展示的组件errorComponent: ErrorComponent,// 如果提供了一个 timeout 时间限制,并超时了// 也会显示这里配置的报错组件,默认值是:Infinitytimeout: 3000
})

如果提供了一个加载组件,它将在内部组件加载时先行显示。在加载组件显示之前有一个默认的 200ms 延迟——这是因为在网络状况较好时,加载完成得很快,加载组件和最终组件之间的替换太快可能产生闪烁,反而影响用户感受。

如果提供了一个报错组件,则它会在加载器函数返回的 Promise 抛错时被渲染。你还可以指定一个超时时间,在请求耗时超过指定时间时也会渲染报错组件。

惰性激活 ​

如果你正在使用服务器端渲染,这一部分才会适用。

在 Vue 3.5+ 中,异步组件可以通过提供激活策略来控制何时进行激活。

  • Vue 提供了一些内置的激活策略。这些内置策略需要分别导入,以便在未使用时进行 tree-shake。

  • 该设计有意保持在底层,以确保灵活性。将来可以在此基础上构建编译器语法糖,无论是在核心还是更上层的解决方案 (如 Nuxt) 中实现。

在空闲时进行激活​

通过 requestIdleCallback 进行激活:

js

import { defineAsyncComponent, hydrateOnIdle } from 'vue'const AsyncComp = defineAsyncComponent({loader: () => import('./Comp.vue'),hydrate: hydrateOnIdle(/* 传递可选的最大超时 */)
})

在可见时激活​

通过 IntersectionObserver 在元素变为可见时进行激活。

js

import { defineAsyncComponent, hydrateOnVisible } from 'vue'const AsyncComp = defineAsyncComponent({loader: () => import('./Comp.vue'),hydrate: hydrateOnVisible()
})

可以选择传递一个侦听器的选项对象值:

js

hydrateOnVisible({ rootMargin: '100px' })

在媒体查询匹配时进行激活​

当指定的媒体查询匹配时进行激活。

js

import { defineAsyncComponent, hydrateOnMediaQuery } from 'vue'const AsyncComp = defineAsyncComponent({loader: () => import('./Comp.vue'),hydrate: hydrateOnMediaQuery('(max-width:500px)')
})

交互时激活​

当组件元素上触发指定事件时进行激活。完成激活后,触发激活的事件也将被重放。

js

import { defineAsyncComponent, hydrateOnInteraction } from 'vue'const AsyncComp = defineAsyncComponent({loader: () => import('./Comp.vue'),hydrate: hydrateOnInteraction('click')
})

也可以是多个事件类型的列表:

js

hydrateOnInteraction(['wheel', 'mouseover'])

自定义策略​

ts

import { defineAsyncComponent, type HydrationStrategy } from 'vue'const myStrategy: HydrationStrategy = (hydrate, forEachElement) => {// forEachElement 是一个遍历组件未激活的 DOM 中所有根元素的辅助函数,// 因为根元素可能是一个模板片段而非单个元素forEachElement(el => {// ...})// 准备好时调用 `hydrate`hydrate()return () => {// 如必要,返回一个销毁函数}
}const AsyncComp = defineAsyncComponent({loader: () => import('./Comp.vue'),hydrate: myStrategy
})


Vue DOM获取

vue 2

1. 使用DOM API直接找元素($el属代表了Vue组件实例所挂载的DOM元素

<script>...mounted () {let elm = this.$el.querySelector('#id')}
</script>

2. refs

使用组件实例的$refs即可拿到组件上ref属性对应的元素。
如果ref属性加在一个组件上,那么拿到的是这个组件的实例,否则拿到的就是dom元素。

<template><div ref="bar">{{ foo }}</div><MyAvatar ref="avatar" />...
</template>
<script>...mounted () {let foo = this.$refs['bar'] // 一个dom元素let avatar = this.$refs['avatar'] // 一个组件实例对象}
</script>

3. 使用自定义指令

Vue提供了自定义指令,官方文档给出了如下的使用方法,其中el就是dom元素的引用

Vue.directive('focus', {// 当被绑定的元素插入到 DOM 中时……inserted: function (el) {// 聚焦元素el.focus()}
})// 在模板中
<template><input v-model="name" v-focus />
</template>
vue 3

直接操作 DOM 元素的样式通常不是 Vue 的推荐做法,因为这样做会绕过 Vue 的响应式系统。

1. 通过ref拿到Dom的引用

 对 div 元素添加 ref 属性,再声明了一个与 ref 属性名称相同的变量,然后通过 [变量名].value 的形式即可获取该 div 元素。

适用:单一 dom 元素或者个数较少的场景

<template><div ref="divRef"></div>
</template>
<script setup>
import {ref} from 'vue'
const divRef = ref(null)
const setStyle = () => {//直接操作domsectionRef.value.style.backgroundColor = '#aaa'sectionRef.value.classList.add('addClass')
}
</script>

2. 通过父容器的 ref 遍历拿到 dom 引用

对父元素添加 ref 属性,并声明一个与 ref 属性名称相同的变量 list,此时通过 list.value 会获得包含子元素的 dom 对象。此时可以通过 list.value.children[index] 的形式获取子元素 dom。

适用:v-for循环生成的固定元素数量场景

<template><div ref="listRef"><div>子元素1</div><div>子元素2</div><div>子元素3</div></div>
</template>
<script setup>
import { nextTick, ref } from 'vue'
const listRef = ref(null)
const checkDom = () => {const len = listRef.value.children.lengthfor (let i = 0; i < len; i++) {console.log(listRef.value.children[i])//循环输出<div>子元素1</div>.....}
}
nextTick(() => {checkDom()
})
</script>

3. 通过子组件 emit 传递 ref

对子组件添加 ref 属性,并声明一个与 ref 属性名称相同的变量 childRef,此时通过 emit 将 childRef.value 作为一个 dom 引用传递出去。

适用:多个页面都可能有操作组件 dom 的场景

4.通过 :ref 将 dom 引用放到数组中

适用:通过 v-for 循环生成的不固定数量或者多种元素的场景。

http://www.lryc.cn/news/479822.html

相关文章:

  • Oracle 第30章:最佳实践与案例研究
  • 第九周预习报告
  • 【分享】这篇教程助力你成为 JavaScript 糕手!(四)
  • 双亲委派模型的破坏
  • Android关机流程知多少?
  • 深入理解指针end(总结篇)
  • C# 程序暂停的两种方式
  • 【LeetCode】【算法】160.相交链表
  • 光伏破局 引领能源革命
  • Jenkins声明式Pipeline流水线语法示例
  • 互联网技术净土?原生鸿蒙开启全新技术征程
  • 关于Django 模型字段 `choices`自定义数据类型的枚举——补充
  • CAP理论的延申--BASE理论
  • 【傻呱呱】phpMyAdmin怎样给特定用户授权特定数据库权限?
  • 『VUE』21. 组件注册(详细图文注释)
  • 如何产看SQL 查询的执行时间
  • 计算机网络——路由器构成
  • 架构师之路-学渣到学霸历程-48
  • HappyChart——一款简单好用的专业绘图软件
  • 【Linux】进程信号全攻略(二)
  • redis用法(二)
  • Python-利用os,tkinter库编写一个伪恶意程序文件(Pro版)
  • Oracle视频基础1.4.4练习
  • GOF的C++软件设计模式的分类和模式名称
  • 有向图的完全可达性(有向图搜索全路径的问题) C#DFs
  • 前端开发实现自定义勾选/自定义样式,可复选,可取消勾选
  • 鸿蒙-promptAction.showToast基于PC屏幕底部提示
  • Vert.x,应用监控 - 全链路跟踪,基于Zipkin
  • Rust常用数据结构教程 序列
  • 智慧城市路面垃圾识别系统产品介绍方案