2022-03-03
阅读:38
##查看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.sexreactive转为代理对象Object.defineProperty()的get与set来实现响应式(数据劫持).value,读取数据时,模板中直接读取不需要.value。.value。this.$attrsthis.$slotsthis.$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 改名为 beforeUnmountdestoryed 改名为 unmountedbeforeCreate > setupcreated==> setupbeforeMount > onBeforeMountmounted  => onMountedbeforeUpdate ===> onBeforeUpdateupdated===> onUpdatedbeforeUnmount => onBeforeUnmountunmounted ==> onUnmountedtoRef作用:创建一个ref对象,其value值指向另一个对象中的某个属性
const name = toRef(person,'name')toRefs与toRef功能一致,但可以创建多个ref对象,(解构,但不失去响应式)
const person = reactive({
name:'张三',
age:20
})
//用展开运算符获取  name,age
return {
...toRefs(person)
}
shallowReactiveshallowRefref变为只读的 (深层次)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)