vue3学习心得

2023-11-11

在这里插入图片描述
关注公众号可获得更多干货

一、vue3是如何变快的

1、 diff 算法
+ Vue2中的虚拟DOM是进行全量对比
+ Vue3新增了静态标记【PatchFlag】

说明:
    
与上次虚拟节点对比,只对比带有静态标记的节点
并且通过flag的信息能得知当前要对比的内容
<div>
	<p>这是一个例子</p>
	<p>{{msg}}</p>
</div>

DOM树


2、 hoist static 静态提升
+ vue2中无论元素是否参与更新,每次都会重新创建,然后渲染
+ vue3中对于不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用即可
3、 事件侦听器缓存
+ 默认情况下onClick事件会被视为动态绑定,所以每次都会追踪他的变化,但是因为是同一个函数,所以没有追踪变化,直接缓存起来复用
4、 ssr渲染
服务端渲染

二、Vite

vue作者试图取代webpack的一个工具
1、使用方式:
1. 安装
    npm install -g create-vite-app
2. 创建项目
    create-vite-app projectName
3. 目录下创建好了项目
    cd projectName
    npm install
    npm run dev

三、 组合api

1、setup函数
import { ref, reactive } from 'vue'
setup(){
    let varA = ref(0)
    function funA() {
        console.log('我是函数')
    }
    return { varA, funA }
}

setup() 函数是一个组合api,在执行组合函数时,会将varA自动注入到data中,会将funA自动注入到methods中。

注意:ref 可以监听基础数据类型数据,reactive 可以监听引用数据类型

1.1、 执行时间
beforeCreate():表示组建刚刚被创建出来。组建的data和methods还么有被创建好
setup()Created():表示组建刚刚被创建出来。组建的data和methods已经被初始化好了

setup()

  • 由于在执行setup函数的时候,还没有执行到Created方法 ,所以还不能使用 data 和 methods 的方法
  • this 为 undefined【因为vue避免我们错误使用,所以将this置为undefined】
  • setup函数必须是同步的不能是异步的
1.2、 什么是reactive?
 reactive是vue3提供的一个响应式数据方法
 在vue2中通过defindProperty来实现的
 在vue3中响应式数据是通过ES6的Proxy实现的

reactive注意点:

  • 值必须是一个对象(json/arr)
  • 如果没有给reactive传递对象,默认情况下给对象修改值,是无法作出页面响应,如果想反映到页面上,则需要给对象重新复值。
1.3、 什么是ref?
  • ref和reactive一样, 也是用来显示响应式数据的方法
  • 犹豫reactive必须传递一个对象,所以导致在企业开发中如果我们只想让某一个变量实现响应式的时候就会非常麻烦,所以vue3就给我们提供了ref方法,实现对简单值的监听
1.4、 ref本质:
  • 底层的本质其实还是reactive,系统会自动根据我们传入的ref值将他转换成
    ref(10) ===> reactive({value:10})

ref注意点:

  • 在vue中的template中使用ref的值不用通过value获取
  • 在js中使用ref的值必须通过value获取
1.5、ref和reactive的区别
  • 如果在template里使用的是ref类型的数据,vue会自动帮我们添加.value

  • 如果在template里使用的是reactvie类型的数据,vue不会自动帮我们添加.value

     vue是如何决定是否需要自动添加.value的?
      
     vue在解析数据之前,会自动判断这个数据是否是ref类型的,如果是ref类型的数据就自动添加.value,如果不是就不自动添加.vlaue
    
1.6、vue是如何判断当前数据是否为ref类型的

通过当前数据的 __v_ref来判断的
如果有__v_ref这个私有属性的hauler,并且值为true,那么代表就是一个ref类型的数据
在这里插入图片描述

1.7、vue中给我们提供了isRef(),isReactive()函数

__v_ref为私有属性,所以vue3提供了isRef(),isReactive()函数来判断当前变量是什么类型的数据。

	import { ref, reactive, isRef, isReactive } from 'vue'
	let age = ref(12)
	let state = reactive({
		name: 'bob'
	})
	isRef(age); //true
	isRef(state);//false
	isReactive(age);//false
	isReactive(state);//true

四、 递归监听 与 非递归监听

4.1、存在的问题:如果数据量比较大,非常消耗性能
import { ref, reactive, isRef, isReactive } from 'vue'
let obj1 = ref({
	a:"a",
	grandfather:{
		b:"b",
		father:{
			c:"c",
			son:{
				d:"d"
			}
		}
	}
})
let obj2 = reactive({
	a:"a",
	grandfather:{
		b:"b",
		father:{
			c:"c",
			son:{
				d:"d"
			}
		}
	}
})

上面情况默认使用的是递归监听,打印其本身,ref第一层是一个ref对下你给,reactive的每一层都是一个Proxy对象,只要改变某一个值,都会更新到页面上

4.2、非递归监听
	import { shallowRef, shallowReactive } from 'vue'

非递归监听就是,视图只能监听到数据第一层变化,而监听不到更深层的变化。这两个函数创建出来变量是非递归监听的,只为某个对象的私有(第一层)属性创建浅层的响应式代理,不会对“属性的属性”做深层次、递归地响应式代理,而只是保留原样。

注意:
 如果通过shallowRef创建数据,那么vue监听的是.value的变化,并不是第一层的变化
import { triggerRef } from 'vue'

使用triggerRef(obj1)方法则可对shallowRef方法类型的数据做到页面更新

注意:
vue3只提供了triggerRef的方法,没有提供triggerReactive方法
所以如果是reactive类型的数据,那么是无法主动触发界面更新

在这里插入图片描述

import { shallowRef, shallowReactive } from 'vue'
import { triggerRef } from 'vue'
setup() {
        let person = shallowRef({
            a: 'a',
            gf: {
                b: 'b',
                f: {
                    c: 'c',
                    s: {
                        d: 'd'
                    }
                }
            }
        })
        function change() {
            person.value.a = 1  		//因为是shallowRef所以需要修改.vlaue属性
            person.value.gf.b = 2
            person.value.gf.f.c = 3
            person.value.gf.f.s.d = 4
            triggerRef(person)		// 使用该方法,页面才可以监听变化
        }
        return { change,person }
    }

上面代码若不调用triggerRef函数,也可以整体给person.value的值更新,也可更新视图

person.value = {
	a: '1',
    gf: {
        b: '2',
        f: {
            c: '3',
            s: {
                d: '4'
            }
        }
    }
}
setup() {
        let obj = shallowReactive({
            a: 'a',
            gf: {
                b: 'b',
                f: {
                    c: 'c',
                    s: {
                        d: 'd'
                    }
                }
            }
        })
        function change() {
            console.log(obj)
            obj.a = 1			//此时如果注释掉第一层变量修改值,则页面无法监听数据变化,若一层数据也会修改,则整体数据就会重新渲染
            // obj.gf.b = 2
            // obj.gf.f.c = 3
            obj.gf.f.s.d = 4

        }
        return { obj, change}
    }
4.3、 应用场景

一般情况下我们使用 ref 和 reactive即可,只有我们在需要监听的数据量比较大的时候,我们才使用shallowRef/shallowReactive提供监听

4.4、 shallowRef底层原理
ref -> reactive
ref(10) -> reactive({value:10})
shallowRef -> shallowReactive
shallowRef(10) -> shallowReactive({value:10})

所以如果是通过shallowRef创建的数据,他监听的是.value的变化
因为底层本质上vlaue才是第一层

五、 toRaw()

import { reactive } from 'vue'
setup() {
	let obj = {
		name:'张三',
		age: 18
	}
	let state = reactive(obj)
	console.log(obj === state) //false 
	/*
		state 和 obj 的关系
		引用关系,state的本质是一个Proxy对象,在这个Proxy对象中引					用了obj
	*/

	let changeData = function() {
		obj.name = 'lisi'
		// 修改了obj对象中一个属性,obj和state引用中都已修改,但是视图数据不变
		// 若想视图变化,需要修改包装后的对象。才能触发视图的更新
		state.obj.name = 'wangwu'
	}
	return {state,changeData}
	
}

toRaw()函数是 获取ref和reactive类型数据的原始数据

ref/reactive类型数据的特点:
每次修改都会被追踪,都会更新UI界面,但是这样其实是非常消耗性能的,所以如果我们有一些操作不需要追踪,不需要更新UI界面,那么这时候,就可以通过toRaw方法拿到他的原始数据,对原始数据进行修改,这样就不会被追踪,也不会更新UI界面,从而来优化性能
import { reactive, toRaw } from 'vue'
setup() {
	let obj = {
		name:'张三',
		age: 18
	}
	let state = reactive(obj)
	let obj2 = toRaw(state)
	console.log(obj === obj2) //true

	let changeData = function() {
		// 此时调用修改数据方法,则页面ui不会更新,但数据已经修改 
		obj2.name = 'lisi'
	}
	return {state,changeData}
}

ref 的本质: reactive

	ref(obj) -> reactive({value:obj})

注意:
如果想通过toRaw拿到ref类型的原始数据(创建时传入的按那个数据),那么就必须明确的告诉toRaw方法,要获取的是.value的值,因为经过Vue处理后,.value中保存的才是当初创建时传入的那个原始数据

import { ref, toRaw } from 'vue'
setup() {
	let obj = {
		name:'张三',
		age: 18
	}
	let state = ref(obj)
	let obj2 = toRaw(state)
	console.log(obj)
	console.log(state)
	console.log(obj2) //此时obj2 并不是{name:'张三',age:18}
	let obj3 = toRaw(state.value)
	console.log(obj3) // {name:'张三',age:18}
	
	return {state}
}

六、 markRaw()

对数据永远不追踪,数据如何修改都不会响应到UI上

import {reactive,markRow} from 'vue'
setup() {
	let obj = {
		name: 'zhangsan',
		age:18
	}
	obj = markRow(obj)
	let state = reactive(obj)
	function changeFn() {
		// 此时执行函数无法修改数据
		state.name = 'lisi'
	}
	return { state, changeFn }
}

七、 toRef(),toRefs()

toRef()
import { ref } from 'vue'
setup() {
	let obj = { name:'zhangsan' }
	/*
		ref(obj.name) => ref('zhangsan') => reactive({value:'zhangsan'})
		ref => 复制
	*/
	let state = ref(obj.name)
	function changeData() {
		state.value = 'zs'
		/*
			使用ref将某一个对象中的属性变成响应式数据,我们修改响应式的数据是不会影响到原始数据的。
		*/
	}
	return { state,changeData }
}
import { ref, toRef } from 'vue'
setup() {
	let obj = { name:'zhangsan' }
	/*
		toRef => 引用
	ref与toRef的区别:
		ref => 复制,修改响应式数据不会影响原始数据;数据改变,界面就会自动更新
		toRef => 引用,修改响应式数据会影响原始数据的改变;数据改变,界面不会更新
	toRef应用场景:
		如果想让响应式数据和以前的数据关联起来,并且更新响应式数据之后还不想更新UI,就可食用toRef
	*/
	let state = toRef(obj,'name')
	console.log(state)
	function changeData() {
		state.value = 'zs' // 会修改到 obj 的 name 属性
		/*
			使用toRef将某一个对象中的属性变成响应式数据,我们修改响应式的数据是会影响到原始数据的。
			但是如果响应式的数据是通过toRef创建的,那么修改数据并不会触发界面UI的更新
		*/
	}
	return { state,changeData }
}
toRefs()

需求:若想讲一个对象中若干属性都改为响应式属性

import { toRef } from 'vue'
setup() {
	let obj = { name:'zhangsan', age:18 }

	let name = toRef(obj,'name')
	let age = toRef(obj,'age')
	
	function changeData() {
		name.value = 'zs'
		age.value = 20
	}
	return { name, age, changeData }
}
import { toRefs } from 'vue'
setup() {
	let obj = { name:'zhangsan', age:18 }
	let state = toRefs(obj)
	
	function changeData() {
		state.name.value = 'zs'
		state.age.value = 20
	}
	return { state, changeData }
}
customRef

自定义Ref函数:返回一个ref对象,可以显示地控制以来追踪和触发响应式,定义customRef时,我们要在获取值时告诉vue数据要追踪变化,使用track()方法,在设置值时告诉vue要触发页面更新,使用trigger()

语法:
customRef((track,trigger) => {
	return {
		// 获取值
		get() {
			track(); // 告诉vue这个数据是需要追踪变化的
			cosnole.log('get',value)
			return value
		},
		// 设置值
		set(newValue) {
			cosnole.log('newValue',newValue)
			value = newValue
			trigger(); // 告诉vue要触发页面更新
		}
	}
})
import { ref,customRef } from 'vue'

function myRef(value) {
	return customRef((track,trigger) => {
		return {
			// 获取值
			get() {
				track(); // 告诉vue这个数据是需要追踪变化的
				cosnole.log('get',value)
				return value
			},
			// 设置值
			set(newValue) {
				cosnole.log('newValue',newValue)
				value = newValue
				trigger(); // 告诉vue要触发页面更新
			}
		}
	})
}
export default{
	name: 'App',
	setup() {
		// let age = ref(18)
		let age = myRef(18)
		function myFn() {
			age.value ++ 
		}
		return {age,myFn}
	}
}

八、ref补充

如何获取页面元素?

若在组合函数setup中获取,该函数的执行顺序在created之前,元素还没有创建,所以无法获取到元素;但setup中也可以监听钩子函数:

<template>
	<div ref="box">我是div</div>
</template>
/*
beforeCreate
setup
created
*/
import { ref, onMounted } from 'vue'
setup() {
	let box = ref(null); // reactive({value:null})
	// 会执行生命周期函数
	onMounted(() => {
		console.log('onMounted',box.value) // <div ref="box">我是div</div>
	})

	consooe.log(box.value); //null
	return { box }
}

九、readonly,shallowReadonly, isReadonly

readonly 创建只读数据,并且是递归只读,所有属性都不可修改
shallowReadonly 创建只读数据,不是递归只读,只对首层属性只读
isReadonly 判断是否为只读数据

import { readonly, isReadonly, shallowReadonly } from 'vue'

export default {
    name: 'test',
    setup() {
        let person = readonly({ name: 'zhangsan', attr: { age: 13, height: 188 } })

        let women = shallowReadonly({ name: 'Alice', attr: { age: 20, height: 165 } })

        function btnFn() {
            console.log('person1', person) // 原样输出
            person.name = 'lisi' // 报出警告,说该属性是只读属性无法修改
            person.attr.age = 20 // 报出警告,说该属性是只读属性无法修改
            console.log('person2', person) // 原样输出

            console.log('women1', women) // 原样输出
            women.name = 'lisi' // 报出警告,说该属性是只读属性无法修改
            women.attr.age = 30 // 修改生效,但UI界面没有更新
            console.log('women2', women) // 原样输出
            
			console.log("person", isReadonly(person)) // true
            console.log("women", isReadonly(women)) // true
        }
        return { person, women, btnFn }
    }
}
9.1和const 区别

const:赋值保护,不能给变量重新赋值
readonly: 属性保护,不能给属性重新赋值

let { readonly } from 'vue'
setup() {
	const man = { name: 'Bob', age: 13 };
	let woman = readonly({ name: 'Alice', age: 12 })
	
	function changeVal() {
		man.age = 14 // man的age属性修改
		woman.age = 15 //报出警告,属性为只读,不可修改
		man = "123" // 报错,无法修改
		woman = "123" // woman被修改为123
	}
	
	return { man, woman, changeVal }
	
}

十、Vue3 响应式数据本质

通过Proxy方法封装了数据,来设置监听,在给变量赋值时会走到Proxy方法重的set方法,在set方法中修改完值去更新UI界面

let obj = { name: 'Bob', age: 18 }
let state = new Proxy(obj,handler: {
	get(obj,key) {
		console.log(obj,key) // { name: 'Bob', age: 18 } name
		return obj[key]
	}
	set(obj, key, value) {
		console.log(obj,key,value) // { name: 'Bob', age: 18 } name 鲍勃
		obj[key] = value
		console.log('更新UI界面')
	}
})
console.log(state.name)
state.name = "鲍勃"

set方法必须通过返回值告诉Proxy此次操作是否成功

let arr = [1,3,5]

let state = new Proxy(arr,handler: {
	get(obj,key) {
		console.log(obj,key) // [1,3,5] 1
		return obj[key]
	}
	set(obj, key, value) {
		console.log(obj,key,value)
		//  [1,3,5]  3  7   先将数组最后插入一个7
		//  [1,3,5,7] length 4  再将数组长度改为4
		obj[key] = value
		console.log('更新UI界面')
		return true     // 这个是一个返回值,告诉本次操作成功,才能执行再一次操作,因为修改数组时,第一步修改数组数据,第二步修改数组长度
	}
})

console.log(state[1]) // 3
state.push(7) // [1,3,5,7]

手写shallowReactive, shallowRef

shallowReactive

function shllowReactive(obj) {
    return new Proxy(obj, {
        get(obj, key) {
            return obj[key]
        },
        set(obj, key, value) {
            obj[key] = value
            console.log('更新UI界面')
            return true
        }
    })
}
let obj = {
    a: "a",
    gf: {
        b: "b",
        f: {
            c: "c",
            s: {
                d: "d"
            }
        }
    }
}

let test = shllowReactive(obj)
test.a = "1" // 会更新ui界面,若不修改第一层,则不会输出“更新UI界面”

shallowRef

function shallowRef(val) {
    shllowReactive({ value: val })
}
function shllowReactive(obj) {
    return new Proxy(obj, {
        get(obj, key) {
            return obj[key]
        },
        set(obj, key, value) {
            obj[key] = value
            console.log('更新UI界面')
            return true
        }
    })
}
let obj = {
    a: "a",
    gf: {
        b: "b",
        f: {
            c: "c",
            s: {
                d: "d"
            }
        }
    }
}

let test = shallowRef(obj)
test.value = {
	a: "1",
    gf: {
        b: "2",
        f: {
            c: "3",
            s: {
                d: "4"
            }
        }
    }
}

手写reactive, ref

function ref(val) {
    reactive({ value: val })
}
function reactive(obj) {
	// 递归判断属性是否为对象,如果为对象则将对象继续创建为Proxy
    if (typeof obj === 'object') {
        if (obj instanceof Array) {
            obj.forEach((item, index) => {
                if (typeof item === 'object')
                    obj[index] = reactive(obj[index])

            })
        } else {
            for (let key in obj) {
                if (typeof obj[key] === 'object')
                    obj[key] = reactive(obj[key])
            }
        }
    }
    return new Proxy(obj, {
        get(obj, key) {
            return obj[key]
        },
        set(obj, key, value) {
            obj[key] = value
            console.log('更新UI界面')
            return true
        }
    })
}

let obj = {
    a: "a",
    gf: {
        b: "b",
        f: {
            c: "c",
            s: {
                d: "d"
            }
        }
    }
}

let test = reactive(obj)
function btnFn() {
    test.a = "1"
    test.gf.b = "2"
    test.gf.f.c = "3"
    test.gf.f.s.d = "4"
    console.log('change test', test)
}

let arr = [{ name: 'bob', attr: { sex: 'boy', age: 12 } }, { name: 'alice', attr: { age: 16 } }]

let arrReactive = reactive(arr)

function changeArr() {
    arr[0].name = "特朗普"
    arr[0].sex = "1"
    arr[1].age = "89"
}

let state = ref(123)
function changeRef() {
    console.log(state)
    state.value = 345
}

在这里插入图片描述
关注公众号可获得更多干货

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vue3学习心得 的相关文章

  • 离线安装Nginx(rpm方式)

    环境 centos7 9 下面将展示通过rpm方式安装Nginx 1 官方下载Nginx rpm包 下载地址 http nginx org packages 下载版本根据操作系统版本进行选择 本次操作系统是centos7 9 64位系统 所

随机推荐

  • dbcp

    initialSize 10 初始化连接 连接池启动时创建的初始化连接数量 默认值为0 maxActive 80 最大活动连接 连接池中可同时连接的最大的连接数 默认值为8 minIdle 10 最小空闲连接 连接池中最小的空闲的连接数 低
  • 30个Python极简代码

    Python 是机器学习最广泛采用的编程语言 它最重要的优势在于编程的易用性 如果读者对基本的 Python 语法已经有一些了解 那么这篇文章可能会给你一些启发 作者简单概览了 30 段代码 它们都是平常非常实用的技巧 我们只要花几分钟就能
  • webpack 模块加载兼打包工具——入门或进阶

    一 说点废话 1 webpack 是以 commonJS 的形式来书写脚本滴 但对 AMD CMD 的支持也很全面 方便旧项目进行代码迁移 2 能被模块化的不仅仅是 JS 了 3 开发便捷 能替代部分 grunt gulp 的工作 比如打包
  • 【Linux】Linux编程之 mmap解析

    前言 虚拟内存系统通过将虚拟内存分割为称作虚拟页 Virtual Page VP 大小固定的块 一般情况下 每个虚拟页的大小默认是4096字节 同样的 物理内存也被分割为物理页 Physical Page PP 也为4096字节 一 mma
  • Nuxt脚手架nuxi初始化失败原因&解决方法

    起因 前几天终于把毕业设计的开题报告整完了 有了一点时间干自己的事 于是就想着学学nuxt3 结果发现跟着官方教程敲的第一行命令就出现了问题 npx nuxi init nuxt3 app 这行代码是nuxt的脚手架 会生成一个最简单的模板
  • 连接器链调用---Spring源码从入门到精通(二十三)

    上篇文章主要介绍了methodInterceptor拦截器吧增强组件返回的过程 获取拦截器链MethodInterceptor Spring源码从入门到精通 二十二 这篇文章主要介绍拦截器链如何触发 一 拦截器链的触发过程 1 首先第一个判
  • 比Mojo慢68000倍,Python性能差的锅该给GIL吗?

    关注并星标腾讯云开发者 每周1 鹅厂工程师带你审判技术 第3期 李志瑞 天使还是魔鬼 聊聊 Python GIL 9 月 7 日 新兴编程语言 Mojo 正式发布 Mojo 的最初设计目标是比 Python 快 35000 倍 近期该团队表
  • Unity Hub登录无响应

    以下是我遇到的问题以及解决方案 在此之前这篇博文说的也很不错 可以参考一下 Unity Hub 3 登录无响应 无法登录 解决方式 主要是看能不能弹出来登录窗口 找了半天的解决方案 最终发现是默认浏览器的锅 去设置里改一下web浏览器 我用
  • web性能测试

    专业的软件测试工程师至少要掌握一到两种测试工具 而作为普通软件开发者 或多或少掌握一些测试方法和技巧 随着用户对科技产品用户体验度的上升 产品发布前的测试工作变得尤为重要 工欲善其事必先利其器 下面本文就推荐五款非常流行的Web性能测试工具
  • 对126邮箱进行自动化测试

    打开126邮箱页面 输入邮箱和密码 并点击企业邮箱 from selenium import webdriver import time dr webdriver Chrome dr get https mail 126 com time
  • [日记]LeetCode算法·二十五——二叉树⑤ AVL树(插入+删除)附代码实现

    本章的代码实现基于上一篇BST与优先队列的基类进行平衡二叉树 即AVL树 文章目录 AVL的概念 AVL查询效率 AVL的插入 1 插入节点 2 更新平衡因子BF 3 旋转调整树的结构 3 1 LL 右旋 3 2 RR 左旋 3 3 LR
  • 分布式系统数据同步问题

    分布式系统 通过数据冗余 来保证数据的安全 要写一个分布式系统 一道绕不过去的坎 那就是数据同步 同步 这两个字 折磨死了很多人 是同步 还是异步 是push 还是pull 谁是master 谁是slave 下线会怎样 上线了又会怎样 中心
  • 11个值得珍藏的4K高清壁纸网站推荐

    前言 由于前几天因需求须找一些视觉素材 翻来覆去整了一些 整理了10个图片素材网站可以给大家收藏使用 作为打开电脑 or 手机第一眼就看到的桌面 给它设置一个赏心悦目的桌面壁纸还是必不可少的 下面分享了 10 个值得珍藏的高清桌面壁纸网站
  • Solidworks渲染技巧如何不显示边线--显示样式设定

    如上图是带边线的显示 如果要出ps效果图 这样的边线存在会让效果图显得难看 因为默认是选定了带边线上色的显示样式 只要改成 上色 第二种的显示样式 即可不会带边线 另外如果想得到纯白色的背景色 选择应用布景选单白色 快速选择渲染颜色的技巧
  • protobuf安装教程

    protobuf安装 一 Windows下安装 下载protobuf 配置环境变量 检查是否安装成功 二 Linux下安装 下载protobuf 安装protobuf 检查是否安装成功 一 Windows下安装 下载protobuf 下载地
  • 在浏览器加载完毕后,自动播放视频:出现play() failed because the user didn't interact with the document first.错误

    问题 test html 30 Uncaught in promise DOMException play failed because the user didn t interact with the document first ht
  • 查看nginx版本号的几种方法

    1 查看服务器上安装的nginx版本号 主要是通过nginx的 v或 V选项 查看方法如下图所示 v 显示 nginx 的版本 V 显示 nginx 的版本 编译器版本和配置参数 root zq nginx V nginx version
  • 欧拉角、四元数、旋转矩阵推导及相互关系

    Tags SLAM 一 旋转与旋转矩阵 1 2D旋转 2 3D旋转 二 欧拉角 三 四元数 四 相互转换 1 四元数转旋转矩阵 2 旋转矩阵转四元数 3 欧拉角转旋转矩阵 4 旋转矩阵转欧拉角 5 欧拉角转四元素 6 四元数转欧拉角 五 参
  • Python循环语句(while)(for)经典简单练习题

    求100以内所有偶数的和 sum 0 定义求和的数从0开始 for i in range 0 101 2 利用for循环语句定义i在0到100之间 由左 闭右开的原则 i可以取到0 但是取不到101 故i在0到100之间 再定义每两 个数之
  • vue3学习心得

    关注公众号可获得更多干货 一 vue3是如何变快的 1 diff 算法 Vue2中的虚拟DOM是进行全量对比 Vue3新增了静态标记 PatchFlag 说明 与上次虚拟节点对比 只对比带有静态标记的节点 并且通过flag的信息能得知当前要