首页 > 其他分享 >Vue3.3 编译宏

Vue3.3 编译宏

时间:2023-07-29 20:32:53浏览次数:45  
标签:node name ctx prop Vue3.3 编译 组件 DEFINE

Vue3.3 编译宏_Vue.js

Vue 3.3新增了一些语法糖和宏,包括泛型组件、defineSlots、defineEmits、defineOptions

defineProps

  • 父子组件传参
<template>
 <div>
    <Child name="xiaoman"></Child>
 </div>
</template>
 <script lang='ts' setup>
 import Child from './views/child.vue'
</script>
<style></style>

子组件使用defineProps接受值

<template>
 <div>
     {{ name }}
 </div>
</template>
 <script  lang='ts' setup>
 defineProps({
     name: String
 })
</script>
  • 使用TS字面量模式
<template>
 <div>
     {{ name }}
 </div>
</template>
 <script  lang='ts' setup>
 defineProps<{
    name:string
 }>()
</script>
  • Vue3.3 新增 defineProps 可以接受泛型
<Child :name="['xiaoman']"></Child>
 //-------------子组件-----------------
 <template>
 <div>
     {{ name }}
 </div>
</template>
 <script generic="T"  lang='ts' setup>
 defineProps<{
    name:T[]
 }>()
</script>

defineEmits

  • 父组件
<template>
 <div>
    <Child @send="getName"></Child>
 </div>
</template>
 <script lang='ts' setup>
 import Child from './views/child.vue'
 const getName = (name: string) => {
     console.log(name)
 }
</script>
<style></style>

子组件常规方式派发Emit

<template>
 <div>
    <button @click="send">派发事件</button>
 </div>
</template>
 <script  lang='ts' setup>
const emit = defineEmits(['send'])
const send = () => {
    // 通过派发事件,将数据传递给父组件
    emit('send', '我是子组件的数据')
}
</script>

子组件TS字面量模式派发

<template>
 <div>
    <button @click="send">派发事件</button>
 </div>
</template>
 <script  lang='ts' setup>
const emit = defineEmits<{
    (event: 'send', name: string): void
}>()
const send = () => {
    // 通过派发事件,将数据传递给父组件
    emit('send', '我是子组件的数据')
}
</script>

Vue3.3 新写法更简短

<template>
 <div>
    <button @click="send">派发事件</button>
 </div>
</template>
 <script  lang='ts' setup>
const emit = defineEmits<{
    'send':[name:string]
}>()
const send = () => {
    // 通过派发事件,将数据传递给父组件
    emit('send', '我是子组件的数据')
}
</script>

defineExpose

没变化

defineExpose({
    name:"张三"
})

defineSlots

  • 父组件
<template>
    <div>
        <Child :data="list">
            <template #default="{item}">
                   <div>{{ item.name }}</div>
            </template>
        </Child>
    </div>
</template>
<script lang='ts' setup>
import Child from './views/child.vue'
const list = [
    {
        name: "张三"
    },
    {
        name: "李四"
    },
    {
        name: "王五"
    }
]
</script>
<style></style>

子组件 defineSlots只做声明不做实现 同时约束slot类型

<template>
 <div>
     <ul>
        <li v-for="(item,index) in data">
            <slot :index="index" :item="item"></slot>
        </li>
     </ul>
 </div>
</template>
 <script generic="T"  lang='ts' setup>
defineProps<{
    data: T[]
}>()
defineSlots<{
   default(props:{item:T,index:number}):void
}>()
</script>

defineOptions

  • 主要是用来定义 Options API 的选项

常用的就是定义name 在seutp 语法糖模式发现name不好定义了需要在开启一个script自定义name现在有了defineOptions就可以随意定义name了

defineOptions({
    name:"Child",
    inheritAttrs:false,
})

defineModel

由于该API处于实验性特性 可能会被删除暂时不讲

warnOnce(
    `This project is using defineModel(), which is an experimental ` +
      `feature. It may receive breaking changes or be removed in the future, so ` +
      `use at your own risk.\n` +
      `To stay updated, follow the RFC at https://github.com/vuejs/rfcs/discussions/503.`
  )

源码解析

  • core\packages\compiler-sfc\src\script\defineSlots.ts
export function processDefineSlots(
  ctx: ScriptCompileContext,
  node: Node,
  declId?: LVal
): boolean {
  //是否调用了defineSlots
  if (!isCallOf(node, DEFINE_SLOTS)) {
    return false
  }
  //是否重复调用了defineSlots
  if (ctx.hasDefineSlotsCall) {
    ctx.error(`duplicate ${DEFINE_SLOTS}() call`, node)
  }
  //函数将 ctx 对象的 hasDefineSlotsCall 属性设置为 true,表示已经调用了 DEFINE_SLOTS 函数
  ctx.hasDefineSlotsCall = true

  //然后函数检查传递给 DEFINE_SLOTS 函数的参数个数是否为零,如果不是,则函数抛出错误,指示 DEFINE_SLOTS 函数不接受参数。
  if (node.arguments.length > 0) {
    ctx.error(`${DEFINE_SLOTS}() cannot accept arguments`, node)
  }
//接下来,如果函数接收到了一个可选的表示插槽定义的标识符的节点对象,
//则函数使用 ctx.s.overwrite 
//方法将该节点对象替换为一个表示使用插槽的帮助函数的调用
  if (declId) {
    ctx.s.overwrite(
      ctx.startOffset! + node.start!, //开始位置
      ctx.startOffset! + node.end!, //结束位置
      `${ctx.helper('useSlots')}()` //替换的内容 此时就拥有了类型检查
    )
  }

  return true
}
  • core\packages\compiler-sfc\src\script\defineOptions.ts
export function processDefineOptions(
  ctx: ScriptCompileContext,
  node: Node
): boolean {
  //是否调用了defineOptions
  if (!isCallOf(node, DEFINE_OPTIONS)) {
    return false
  }
  //是否重复调用了defineOptions
  if (ctx.hasDefineOptionsCall) {
    ctx.error(`duplicate ${DEFINE_OPTIONS}() call`, node)
  }
  //defineOptions()不能接受类型参数
  if (node.typeParameters) {
    ctx.error(`${DEFINE_OPTIONS}() cannot accept type arguments`, node)
  }
  //defineOptions()必须接受一个参数
  if (!node.arguments[0]) return true

  //函数将 ctx 对象的 hasDefineOptionsCall 属性设置为 true,表示已经调用了 DEFINE_OPTIONS 函数
  ctx.hasDefineOptionsCall = true
  //函数将 ctx 对象的 optionsRuntimeDecl 属性设置为传递给 DEFINE_OPTIONS 函数的参数
  ctx.optionsRuntimeDecl = unwrapTSNode(node.arguments[0])

  let propsOption = undefined
  let emitsOption = undefined
  let exposeOption = undefined
  let slotsOption = undefined
  //遍历 optionsRuntimeDecl 的属性,查找 props、emits、expose 和 slots 属性
  if (ctx.optionsRuntimeDecl.type === 'ObjectExpression') {
    for (const prop of ctx.optionsRuntimeDecl.properties) {
      if (
        (prop.type === 'ObjectProperty' || prop.type === 'ObjectMethod') &&
        prop.key.type === 'Identifier'
      ) {
        if (prop.key.name === 'props') propsOption = prop
        if (prop.key.name === 'emits') emitsOption = prop
        if (prop.key.name === 'expose') exposeOption = prop
        if (prop.key.name === 'slots') slotsOption = prop
      }
    }
  }
  //禁止使用defineOptions()来声明props、emits、expose和slots
  if (propsOption) {
    ctx.error(
      `${DEFINE_OPTIONS}() cannot be used to declare props. Use ${DEFINE_PROPS}() instead.`,
      propsOption
    )
  }
  if (emitsOption) {
    ctx.error(
      `${DEFINE_OPTIONS}() cannot be used to declare emits. Use ${DEFINE_EMITS}() instead.`,
      emitsOption
    )
  }
  if (exposeOption) {
    ctx.error(
      `${DEFINE_OPTIONS}() cannot be used to declare expose. Use ${DEFINE_EXPOSE}() instead.`,
      exposeOption
    )
  }
  if (slotsOption) {
    ctx.error(
      `${DEFINE_OPTIONS}() cannot be used to declare slots. Use ${DEFINE_SLOTS}() instead.`,
      slotsOption
    )
  }

  return true
}

标签:node,name,ctx,prop,Vue3.3,编译,组件,DEFINE
From: https://blog.51cto.com/u_13463935/6895152

相关文章

  • v831-c-编译环境部署篇
    学了一遍又学回来了,整理整理v831的环境吧头文件这些头文件上面部分是在python里面在编译成可执行文件之前会创造出来的,不用理他下面则是components里面的,需要在.vscode里面设置一下路径这样基本上就可以了,其他的我们不再vscode里面一键操作,就不设置了工具链路径工具链的路......
  • 反编译工具 Fernflower
    反编译.class文件工具Fernflower首先需要下载依赖包 http://the.bytecode.club/fernflower.jar下载后,切换到文件当前目录,直接使用命令 java-jarfernflower.jar目标文件目标路径 进行反编译即可反编译后的文件会生成到指定目录......
  • 01_llvm编译及创建一个module试用llvm
    LLVM源码编译准备好匹配的环境后,我的环境如下:$cat/proc/versionLinuxversion5.4.0-150-generic(buildd@bos03-amd64-012)(gccversion7.5.0(Ubuntu7.5.0-3ubuntu1~18.04))#167~18.04.1-Ubuntu如果环境较老,可checkout到比较老的分支再编,不然容易出现各种软件版本不......
  • ffmpeg 编译安装android和linux
    ffmpeg编译安装android和linux下载:https://github.com/FFmpeg/FFmpeghttps://www.ffmpeg.org/download.htmlenvirenmentndk:https://github.com/android/ndk/wiki/Unsupported-Downloadssudoapt-getinstallbuild-essentialpkg-configsudoapt-getintalllibx264-dev......
  • gcc的编译过程
    一、gcc的编译过程、源文件xxx.c预处理文件xxx.i汇编文件xxx.s未链接的二进制文件xxx.o通过连接,产生最终可执行的二进制文件二、编译步骤的工作1、预处理头文件被包含进来(复制):#include宏定义会被替换:#define取消宏定义:#undef条件编译:#if#ifde......
  • apue.3e遇到的编译问题(recipe for target 'badexit2' failed)以及ls1.c案例测试
    APUE(慢慢啃这本书)编译问题,网上获得的前辈方法,本地测试可行,仅作记录。1.系统环境2.下载解压tar-zxvf*.tar.gzcd./apue.3emake报错:collect2:error:ldreturned1exitstatusMakefile:31:recipefortarget'badexit2'failedmake[1]:***[badexit2]Error1m......
  • Linux源码安装mysql 5.5.x (cmake编译)
    以下五个软件包是在安装mysql5.5.x之前必须安装的,不然在进行cmake时会报错。这些软件可以通过下面的链接进行源码安装,也可以通过yum安装1.安装make编译器 下载地址: http://www.gnu.org/software/make/ tarzxvfmake-3.82.tar.gzcdmake-3.82./configuremakemakeinstall2.安装b......
  • AndroidAnnotations 自定义控件 ant编译 找不到类
    问题:今天使用jenkins+ant编译android项目,一直编译不通过,报错内容就是,自定义控件找不到类。确认了几次svn提交,项目代码完全提交,所以想到是不是代码的问题。故回头查询代码。在代码中使用了下划线类。这个类是在AA中自动生成的,而报错的地方,正是编译生成的地方,觉得可能和编......
  • m基于OFDM+QPSK和turbo编译码以及MMSE信道估计的无线图像传输matlab仿真
    1.算法仿真效果matlab2022a仿真结果如下:    2.算法涉及理论知识概要       基于OFDM+QPSK和Turbo编码以及MMSE信道估计的无线图像传输是一种高效可靠的无线通信系统,广泛应用于图像传输领域。该系统利用正交频分复用(OFDM)技术,将图像数据分成多个子载波进行传输,......
  • m基于OFDM+QPSK和turbo编译码以及LS信道估计的无线图像传输matlab仿真
    1.算法仿真效果matlab2022a仿真结果如下:   2.算法涉及理论知识概要       正交频分复用(OFDM)技术将图像数据分成多个子载波进行传输,使用QPSK调制对信号进行调制,通过Turbo编码增强信号的纠错能力,并采用LS信道估计技术来估计信道状态。 系统原理:    ......