2022-03-03
阅读:33
##查看vue-cli版本,确保 @vue/cli 版本号在 4.5.0以上
vue -V
##安装或升级 vue脚手架
npm install -g @vue/cli
##创建项目
vue create project-name
##启动项目
cd project-name
npm run serve
官方文档:https://v3.cn.vuejs.org/guide/installation.html#vite
vite官网:https://vitejs.cn/guide/
const xxx = ref(initValue)
Object.defineProperty()
的get与set完成的reactive
函数。ref
函数)const 代理对象 = reactive(源对象)
接收一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象)实现原理:
对象类型:通过Object.defineProperty()
对属性的读取、修改进行拦截(数据劫持)。
数组类型:通过重写更新数组的一系列方法来实现拦截(对数组的变更方法进行了包裹)。
Object.defineProperty(data,'count',{
get(){},
set(){}
})
存在问题
实现原理
通过Proxy(代理):拦截对象中任意属性的变化,包括:属性值的读写、属性的添加、属性的删除等。
通过Reflect(反射):对源对象的属性进行操作。
MDN文档中描述的Proxy与Reflect:
Proxy:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy
Reflect:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect
let person = {
name:'张三',
age:20
}
let p = new Proxy(person,{
get(target,prop){
console.log(`拦截到获取person的${prop}属性`)
console.log(target,prop)
return Reflect.get(target,prop)
},
set(target,prop,value){
console.log(`拦截到设置person的${prop}属性,设置的新值为${value}`)
console.log(target,prop,value)
return Reflect.set(target,prop,value)
},
deleteProperty(target,prop){
console.log(`拦截到删除person的${prop}属性`)
return Reflect.deleteProperty(target,prop)
}
})
//获取name
console.log(p.name)
//修改name
p.name = '李四'
//新增属性
p.sex = '男'
//删除属性
delete p.sex
reactive
转为代理对象Object.defineProperty()
的get
与set
来实现响应式(数据劫持).value
,读取数据时,模板中直接读取不需要.value
。.value
。this.$attrs
this.$slots
this.$emit
。与Vue2.x中的配置功能一致
写法
import { reactive,computed } from 'vue'
export default {
setup(){
let person = reactive({
firstName:'张',
lastName:'三'
})
//计算属性简写(没有考虑计算属性被修改的情况)
let fullName = computed(()=>{
return person.firstName + '-' + person.lastName
})
//计算属性完整写法(考虑读写)
let fullName1 = computed({
get(){
return person.firstName + '-' + person.lastName
},
set(value){
const nameArr = value.split('-')
person.firstName = nameArr[0]
person.lastName = nameArr[1]
}
})
return {
person
}
}
}
与vue2.x中watch配置功能一致
两个小”坑“
监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监视(deep配置失效)。
监视reactive定义的响应式数据中的某个属性时:deep配置有效。
import {ref,reactive,watch} from 'vue'
export default {
setup(){
let name = ref('张三')
let age = ref(20)
//情况一:监听ref定义的响应式数据
watch(name,(newValue,oldValue)=>{
console.log(`name变化了,新值是${newValue},老值是:${oldValue}`)
})
//情况二:监听多个ref定义的响应式数据
watch([name,age],(newValue,oldValue)=>{
console.log(`数据发生变化了,新值是${newValue},老值是${oldValue}`)
//newValue 与 oldValue 数据类型为数组
})
let person = reactive({
name:'张三',
age:20,
list:[{name:'张三',age:10},{name:'李四',age:20}]
})
/**
* 情况三:监视reactive定义的响应式数据
* 1.无法获取到oldValue
* 2.监听是深度监听的 (deep配置无效)
*/
watch(person,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue)
})
/**
* 情况四:监听reactive定义的响应式数据中的某个属性
* 可以正确获取到 oldValue
*/
watch(()=>person.name,(newValue,oldValue)=>{
console.log('name属性变化了',newValue,oldValue)
})
/**
* 情况五:监听reactive 定义的响应式数据中的某些属性
* 可以正确获取到 oldValue
* newValue与oldValue为数组,顺序为watch传入的顺序
*/
watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{
console.log('person改变了',newValue,oldValue)
})
/**
* 特殊情况:监听reactive定义的响应式数据中的某个属性,并且这个属性是对象或数组
* deep有效 (不使用deep无法监听深层属性的变更)
* 无法正确获取 oldValue
*/
watch(()=>person.list,(newValue,oldValue)=>{
console.log('list属性变化了',newValue,oldValue)
},{deep:true})
}
}
watch:既要指明监视的属性,也要指明监视的回调
watchEffect:不用指明监听哪个属性,监视的回调中用到了哪个属性,那就监听哪个属性。
watchEffect有点像computed
//watchEffect所指定的回调中用到的数据只要发生变化了,则执行函数
watchEffect(()=>{
const name = person.name;
console.log('watchEffect配置的回调执行了')
})
beforeDestory
改名为 beforeUnmount
destoryed
改名为 unmounted
beforeCreate
> setup
created
==> setup
beforeMount
> onBeforeMount
mounted
=> onMounted
beforeUpdate
===> onBeforeUpdate
updated
===> onUpdated
beforeUnmount
=> onBeforeUnmount
unmounted
==> onUnmounted
toRef
作用:创建一个ref对象,其value值指向另一个对象中的某个属性
const name = toRef(person,'name')
toRefs
与toRef
功能一致,但可以创建多个ref对象,(解构,但不失去响应式)
const person = reactive({
name:'张三',
age:20
})
//用展开运算符获取 name,age
return {
...toRefs(person)
}
shallowReactive
shallowRef
ref
变为只读的 (深层次)reactive
生成的响应式对象转化为普通对象作用:创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。
例如:实现防抖效果
reactive
对.value
处理为深层的响应式对象(个人理解)<template>
<div>
<input type="text" v-model="text">
<br />
<p>{{text}}</p>
<br />
<br />
<p v-if="person.name">{{person.name}}-----{{person.age}}</p>
<br />
<br />
<div>
<button type="button" @click="addPerson">添加人</button>
<button type="button" @click="changePerson">修改人</button>
</div>
</div>
</template>
<script>
import {customRef, reactive} from 'vue'
export default {
setup(){
//自定义ref
function myRef(value,delay = 200){
let timer
return customRef((track,trigger)=>{
return {
get(){
track() //通知vue追踪value的变化
return value
},
set(newValue){
clearTimeout(timer)
timer = setTimeout(()=>{
value = newValue
console.log('修改值',newValue)
trigger()//通知vue去重新解析模板
},delay)
}
}
})
}
const text = myRef('',0)
const person = myRef({},200)
function addPerson(){
person.value = reactive({name:'张三',age:20})
}
function changePerson(){
person.value.name = '李四'
}
return {
text,
person,
addPerson,
changePerson
}
}
}
</script>
<style>
</style>
作用:实现祖孙组件间通信
父组件中有一个 provide
选项来提供数据,子组件有一个inject
选项来开始使用这些数据
具体写法
祖组件中:
setup(){
let person = reactive({name:'张三',age:20})
provide('person',person)
}
孙组件中:
setup(props,context){
const person = inject('person')
return {
person
}
}
isRef
检查一个值是否为一个ref
或者shallowRef
对象isReactive
检查一个对象是否是由reactive
或 shallowReactive
创建的响应式代理isReadonly
检查一个对象是否是由 readonly
创建的只读代理isProxy
检查一个对象是否是由reactive
或者readonly
方法创建的代理使用传统optionsAPI中,新增或者修改一个需求,就需要分别在data、methods、computed里修改
我们可以更加优雅的组织我们的代码,函数、让相关功能的代码更加有序的组织在一起。
Fragment
虚拟元素中(不参与渲染)什么是 Teleport?——Teleport
是一种能够将我们的组件html结构移动到指定位置的技术。
to
-string
必须是有效的查询选择器 或者 HTMLElement,例如 body, #some-id, .some-classdisabled
-boolean
。此选项可用于禁用 <teleport>
的功能,这意味着其插槽内容将不会移动到任何位置,而是在父组件中指定了<teleport>
的位置渲染。<template>
<div>
<p>移动组件html结构</p>
<teleport to="移动位置" :disable="displayValue">
</teleport>
</div>
</template>
等待异步组件时渲染一些额外的内容,让应用有更好的用户体验
使用步骤:
import {defineAsyncComponent} from 'vue'
const Child = defineAsyncComponent(()=>import('@/components/Child.vue'))
Suspense
包裹组件,并配置好defaule
与fallback
插槽的内容 (defaule为异步组件、fallback为异步组件渲染成功前的展示内容)<template>
<div class="app">
<Suspense>
<Child></Child>
<template v-slot:fallback>
<p>加载中...</p>
</template>
</Suspense>
</div>
</template>
Vue2.x中有许多全局API和配置
//注册全局组件
Vue.components('MyButton',{
data:()=>({
count:0
}),
template:'<button @click="count ++">{{count}}</button>'
})
//注册全局指令
Vue.directive('focus',{
inserted:el=> el.focus()
})
Vue3.0中对这些API做出了调整:
Vue.xxx
调整到应用实例app
上2.x全局API(Vue ) |
3.x实例API(app ) |
---|---|
Vue.config.xxx | app.config.xxx |
Vue.config.productionTip | 移除 |
Vue.component | app.component |
Vue.directive | app.directive |
Vue.use | app.use |
Vue.prototype | app.config.globalProperties |
data选项应始终被声明为一个函数(防止组件被复用时,数据产生关联关系造成干扰)
过渡类名的更改:
.v-enter,
.v-leave-to{
opacity:0;
}
.v-leave,
.v-enter-to{
opacity:1;
}
.v-enter-from,
.v-leave-to{
opacity:0;
}
.v-leave-from,
.v-enter-to{
opacity:1;
}
移除`keyCode
作为v-on
的修饰符,同时也不再支持config.keyCodes
移除v-on.native
修饰符
<myComponent v-on:close="handleClose" v-on:click="handleNativeClick"></myComponent>
<script>
export default{
emits:['close']
}
</script>
移除过滤器(filter)