VCA学习记录

VCA(Vue Composition API)

简介:

在 Vue 3 中,组合式 API(Composition API)是一种用于创建自定义组件的 API,它提供了一种更灵活和可组合的方式来创建组件。

组合式 API 提供了一种将组件的逻辑和样式分离的方法,使您可以更轻松地管理和维护组件的代码。通过使用组合式 API,您可以创建具有更灵活性和可维护性的组件。

优点如下:

  1. 灵活性:组合式 API 允许您将组件的逻辑和样式分离,使您可以更轻松地管理和维护组件的代码。
  2. 可维护性:组合式 API 提供了一种更灵活和可组合的方式来创建组件,使您能够创建具有更灵活性和可维护性的组件。
  3. 可复用性:组合式 API 使您可以创建可复用的组件,从而减少代码冗余并提高代码质量。
  4. 易于测试:组合式 API 使您可以更容易地测试组件,并确保组件的逻辑正确。
  5. 更好的可读性:组合式 API 使组件更易于阅读和理解,并提高了代码的可读性。
  6. 更好的性能:组合式 API 使您能够更好地控制组件的性能,并确保组件在加载速度方面表现良好。

使用

组件中使用VCA

1. 创建响应式变量:reactive,ref,toRef,toRefs
reactive和ref:

​ 两者都可以将一个变量包装成一个响应式对象,区别在于: ref支持对简单数据类型进行包装,并提供value属性用于访问和修改。而reactive是基于proxy对变量进行封装,只支持对对象和数组的封装。

示例代码如下:

setup函数是一个在组件实例创建之前定义组件状态和选项的函数,在此函数中this是无效的

<template>
  <div>{{state.name}}--{{state.age}}</div>
  <div>{{location}}</div>

  <div>{{otherState.name}}-{{otherState.age}}-{{otherState.location}}</div>
  <button @click="changeState">click</button>
</template>

<script>
import {reactive,ref} from "vue";
export default {
  name: "01-reactive和ref",
  setup(){
    // reactive
    const state = reactive({
      name: 'test',
      age:18
    })
    // ref
    const location = ref('NKG')
    //混写
    const otherState = reactive({
      name: 'test',
      age:18,
      location
    })
    const changeState = () => {
      // 操作state
      state.name = 'test1'
      state.age = 20
      //操作ref
      location.value = 'XIAN'
    }
    return {
      state,
      location,
      otherState,
      changeState
    }
  }
}
</script>
<style scoped>

</style>

【注】:ref依然可以实现绑定在dom获取dom节点以及绑定在组件获取组件实例的功能,但是在setup函数中,它是一个包装函数,在使用时,模板中可以直接访问它的值,但在方法中操作时需要用value属性去访问和修改。

toRef,toRefs

toRef用于将对象的某个属性转为响应式,toRefs用于将整个对象的所有属性都转为响应式

用法: 经过toRef和toRefs处理,在模板中使用的感觉更像vue2

<template>
  <div>{{name}}--{{age}}</div>
  <div>{{myName}}--{{myAge}}</div>
</template>

<script>
import {reactive,toRef,toRefs} from "vue";
export default {
  name: "02-toref和torefs",
  setup(){
    const state = reactive({
      name:'test',
      age:18
    })
    const otherState = reactive({
      myName:'test1',
      myAge: 20
    })
    return {
      name: toRef(state.name),
      age: toRef(state.age),
      ...toRefs(otherState)
    }
  }
}
</script>
<style scoped>
</style>

2. 计算属性: computed

计算属性(Computed Property)是一种响应式变量,它通过一个表达式来获取它的值,而不是通过数据访问器(Data Access Tester)来获取。并且只有当计算属性依赖更新的时候才会重新计算,在计算属性中不能进行异步操作。

使用示例: 模糊查询功能:computed接受一个回调函数,返回处理后的数据

<template>
  <input type="text" v-model="state.inputText"/>
  <ul>
    <li v-for="item in computedList" :key="item">{{item}}</li>
  </ul>
</template>

<script>
import {computed, reactive} from 'vue'
export default {
  name: "03-computed",
  setup(){
    const state = reactive({
      inputText:'',
      list: Array(10).fill(0).map((item,index) => `${index}${index}`)
    })
    const computedList = computed(() => state.list.filter(item => item.includes(state.inputText)))
    return{
      state,
      computedList
    }
  }
}
</script>

<style scoped>
</style>

3.侦听器:watch/watchEffect

watch: 监听某个值变化,如果变化可以执行响应的操作
watch具有一定的惰性第一次页面展示的时候不会执行,除非加上immediately,当数据变化的时候才会执行
参数可以拿到当前值和原始值
可以侦听多个数据的变化,用一个侦听器承载,

​ watch的第三个参数是一个对象,{immediate:true,deep:true},immediate表示立即执行,在页面初始化的时候会自动执行,deep表示深度监听一个对象,当对象任意级和任意属性值发生变化时都会执行,因此使用deep:true要特别注意,会十分浪费性能。

watchEffect:
立即执行,没有惰性
自动检查内部代码,代码中有依赖便会执行
不需要传递侦听的内容,会自动感知代码的依赖,不需要传递很多的参数,只需要传递一个回调函数
不能获取之前的值,只能获取当前值
一些异步的操作放在这里会更合适

示例代码:

<template>
  <button @click="handleClick">点击--{{count}}--{{watchEffectCnt}}</button>
  <ul>
    <li v-for="(item,index) in list" :key="index">{{item}}</li>
  </ul>
</template>

<script>
import {ref, watch, watchEffect} from "vue";
export default {
  name: "04-watch",
  setup(){
    const count = ref(1)
    const list = ref([])
    const watchEffectCnt = ref(2)
    const handleClick = () => {
      count.value ++
    }
    // 第一种写法——getter函数
    watch(() => count.value,(newVal,oldVal) => {
      if(newVal){
        setTimeout(() => {
          list.value = Array(10).fill(newVal)
        },2000)
      }
    })
    //第二种写法——响应式变量
    watch(count,(newVal,oldVal) => {
      if(newVal){
        setTimeout(() => {
          list.value = Array(10).fill(newVal)
        },2000)
      }
    })
    // 监听多个变量
    watch([count,watchEffectCnt],(newVal) => {
      if(newVal){
        setTimeout(() => {
          list.value = Array(10).fill(newVal)
        },2000)
      }
    })
    watchEffect((newVal) => {
      watchEffectCnt.value = count.value * 2
    })
    return{
      count,
      handleClick,
      list,
      watchEffectCnt
    }
  }
}
</script>
<style scoped>
</style>

4. props&emit

props用于父组件向子组件传值,emit用于子组件像父组件传值,在VCA的写法中,setup函数的第一个参数是props传过来的所有属性,第二个参数config包含slots、emit、attrs等方法,因此父子组件互相通信可以写成如下方式:
props用于父组件向子组件传值,emit用于子组件像父组件传值,在VCA的写法中,setup函数的第一个参数是props传过来的所有属性,第二个参数config包含slots、emit、attrs等方法,因此父子组件互相通信可以写成如下方式:

// 父组件
<template>
  <child :title="msg" @test="handleClick"></child>
  <button >change--{{msg}}</button>
</template>

<script>
import Child from "./Child.vue";
import {ref} from "vue";
export default {
  name: "App",
  components: {Child},
  setup(){
    const msg = ref('父组件传给子组件的值')
    const handleClick = (value) => {
        debugger
      msg.value = value
    }
    return{
      handleClick,
      msg
    }
  }
}
</script>

<style scoped>
</style>

//子组件
<template>
  {{myTitle}}
  <button @click="handleClick">click--{{myTitle}}</button>
</template>

<script>
import {ref} from "vue";
export default {
  name: "Child",
  props:{
    title:{
      type:String,
      default:''
    }
  },
  setup(props,{emit}){
    const {title} = props
    const myTitle = ref(title)
    const handleClick = () => {
      const childToParent = '子组件给父组件传递的值'
      emit('test',childToParent)
    }
    return{
      myTitle,
      handleClick
    }
  }
}
</script>
<style scoped>
</style>

5. provide&inject

provide和inject可以组合实现非父子跨级通信,在vca中的写法如下:inject和provide都是从vue中引入的

// 父组件
<template>
  <NavBar v-if="isShow"></NavBar>
  <component :is="comName"></component>
</template>
<script>
//getCurrentInstance 获取当前实例
import {getCurrentInstance,ref,provide} from 'vue'
import NavBar from "./components/NavBar.vue";
import List from "./components/List.vue";
import Detail from "./components/Detail.vue";
export default {
  name: "App",
  components:{
    NavBar,List,Detail
  },
  setup(){
    // 获取this
    const _this = getCurrentInstance()
    console.log(_this)
    const comName = ref('List')
    const isShow = ref('isShow')
    provide('comName',comName)
    provide('isShow',isShow)
    return {
      comName,
      isShow
    }
  }
}
</script>

<style scoped>

</style>

// List
<template>
  <div>
    <ul>
      <li v-for="item in state.vcaList" :key="item" @click="handleClick">{{item}}</li>
    </ul>
  </div>
</template>

<script>
import {reactive,inject} from "vue";
export default {
  name: "List",
  setup(){
    const state = reactive({
      vcaList: []
    })
    setTimeout(() => {
      state.vcaList = Array(100).fill(0).map((item,index) => `${index}${index}`)
    })
    let name = inject('comName')
    const handleClick = () => {
      name.value = 'Detail'
    }
    return{
      state,
      handleClick
    }
  }
}
</script>
<style scoped>
</style>

在SPA中使用VCA

在script标签上直接使用setup,
优势: 更少的模板 更简洁的代码
能够使用TS声明props和自定义事件
更好的运行时的性能,其模板会被编译成同一作用域的渲染函数,避免了渲染上下文对象
更好的IDE推理性能,减少了语言服务器从代码中抽取类型的工作
#### 1.单文件组件写法

<template>
  {{computedName}}--{{myMsg}}
  <button v-test @click="handleClick">change</button>
  <Child  title="我是父祖件传递的值" @handleClick="handleRight"></Child>
  <NavBar ></NavBar>
  <div v-cjtest>ddd</div>
<!--  动态组件:支持组件名直接渲染动态组件-->
  <component :is="List"></component>
</template>

<script setup>
import {ref, reactive, toRefs, computed} from "vue";
import List from "./components/List.vue";
import Detail from "./components/Detail.vue";
import NavBar from "./components/NavBar.vue";
import Child from "./Child/child.vue";
let msg = ref('hello')
const state = reactive({
  myMsg: 'world'
})
const {myMsg} = {...toRefs(state)}
const handleClick = () => {
  msg.value = 'test'
  myMsg.value = 'test'
}
const computedName = computed(() => msg.value = msg.value.toUpperCase())
const handleRight = ($event) => {
  console.log($event)
}

//局部指令
const vCjtest = (el) =>{
  console.log(el)
  el.style.background = 'green'
}
</script>
<style scoped>

</style>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值