首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

Vue Vine:带给你全新的 Vue 书写体验!

编程知识
2024年08月04日 21:09

你好,我是 Kagol,个人公众号:前端开源星球

上个月和 TinyVue 的小伙伴们一起参加了 VueConf 24 大会,有幸认识沈青川大佬,并了解了他的 Vue Vine 项目,Vue Vine 让你可以在一个文件中通过函数方式定义多个 Vue 组件,同时可以使用所有 Vue 的模板特性。

听起来是不是很酷!

之前我写过 SFC,也写过 JSX 的 Vue 组件,两者各有缺点。

  • SFC 顾名思义单文件组件,只能在一个文件中定义一个组件,如果有几个相关的组件想放一起,对不起,不行!你只能创建一个文件夹,把一堆相关组件一个一个文件放里面。
  • JSX 虽然能通过函数方式定义组件,并且可以在一个文件中定义多个相关的组件,但是没法享受 Vue 模板语法,以及模板编译相关的优化。

Vue Vine 通过把两者的优点集合在一起,创造了一种全新的 Vue 组件书写方式。

我们来一起体验下吧!

搭建 Vue Vine 环境

假设你已经有一个 Vite + Vue3 项目。

只需要以下步骤,就可以搭建 Vue Vine 环境:

  • 安装 vue-vine 依赖:npm i -D vue-vine
  • 在 vite.config.ts 中导入 VineVitePlugin 插件
import { VineVitePlugin } from 'vue-vine/vite'

export default defineConfig({
  plugins: [
    // ...其他插件
    VineVitePlugin()
  ],
})
  • 安装 VSCode 扩展:Vue Vine

  • tsconfig.json 中配置 macro 类型
{
  "compilerOptions": {
    "types": ["vue-vine/macros"]
  }
}

愉快地体验下 Vue Vine 吧

我们创建一个 MyComponent.vine.ts 文件,写入以下内容:

export function MyComponent() {
  return vine`
    <div>Hello World</div>
  `
}

然后在 App.vue 中引入这个组件。

<script setup lang="ts">
import { MyComponent } from './components/MyComponent.vine'
</script>

<template>
  <MyComponent />
</template>

可以看到显示了一个 Hello World

再定义一个组件,并引入 TinyVue 的组件试试。

MyComponent.vine.ts 文件,写入以下内容:

+ import { TinyButton, TinyAlert } from '@opentiny/vue'

export function MyComponent() {
  return vine`
    <div>Hello World</div>
  `
}

+ export function ComponentDemo() {
+   return vine`
+     <tiny-button type="primary">确定</tiny-button>
+     <tiny-alert description="这是一段描述"></tiny-alert>
+   `
+ }

在 App.vue 中引入这个组件。

<script setup lang="ts">
- import { MyComponent } from './components/MyComponent.vine'
+ import { MyComponent, ComponentDemo } from './components/MyComponent.vine'
</script>

<template>
  <MyComponent />
+   <ComponentDemo />
</template>

用 Vue Vine 方式写一个简单的分页组件

之前在我的博客写过一篇文章:手把手教你使用 Vue / React / Angular 三大框架开发 Pagination 分页组件

我们现在用 Vue Vine 方式重写一遍。

创建 Pagination.vine.ts 文件,写入以下内容:

import { ref } from 'vue'

// 演示组件 props 定义
export function Pagination(props: {
  defaultCurrent: number,
  defaultPageSize: number,
  total: number,
}) {
  // 演示 emit 事件定义
  const emit = vineEmits<{
    change: [current: number]
  }>()

  // 当前页码
  const current = ref(props.defaultCurrent)
  
  // 总页码
  const totalPage = ref(Math.ceil(props.total / props.defaultPageSize))
  
  // 设置当前页码
  const setPage = (page: number) => {
    if (page < 1) return
    if (page > totalPage.value) return
    current.value = page
    emit('change', current.value)
  }

  return vine`
    <div>
      <Button @click="setPage(current - 1)">&lt;</Button>
      {{ current }}
      <Button @click="setPage(current + 1)">></Button>
    </div>
  `
}

// 自定义 Button 组件(演示 <slot></slot> 插槽)
export function Button() {
  const emit = vineEmits<{
    click: []
  }>()

  return vine`
    <button type="button" @click="emit('click')"><slot></slot></button>
  `
}

再定义一个 List 列表组件,用来模拟分页数据。

List.vine.ts

import { ref, watch } from 'vue'

export function List(props: {
  dataSource: {
    id: number
    name: string
  }[]
}) {
  const lists = ref(props.dataSource)

  watch(() => props.dataSource, (newVal) => {
    lists.value = newVal
  })

  return vine`
    <ul>
      <li v-for="list in lists" :key="list.id">
        {{ list.name }}
      </li>
    </ul>
  `
}

在 App.vue 中使用 Pagination 和 List 组件。

<script setup lang="ts">
+ import { ref } from 'vue'
+ import chunk from 'lodash-es/chunk'
import { MyComponent, ComponentDemo } from './components/MyComponent.vine'
+ import { Pagination } from './Pagination.vine'
+ import { List } from './List.vine'
+
+ // 数据源
+ const lists = [
+   { id: 1, name: 'Curtis' },
+   { id: 2, name: 'Cutler' },
+   { id: 3, name: 'Cynthia' },
+   { id: 4, name: 'Cyril' },
+   { id: 5, name: 'Cyrus' },
+   { id: 6, name: 'Dagmar' },
+   { id: 7, name: 'Dahl' },
+   { id: 8, name: 'Dahlia' },
+   { id: 9, name: 'Dailey' },
+   { id: 10, name: 'Daine' },
+ ]
+
+ // 列表当前展示的数据
+ const dataList = ref<{
+   id: number
+   name: string
+ }[]>([])
+
+ const defaultCurrent = 1
+ const defaultPageSize = 3
+ const total = lists.length
+
+ // 设置当前列表数据
+ const setList = (current: number, pageSize: number) => {
+   dataList.value = chunk(lists, pageSize)[current - 1]
+ }
+
+ setList(defaultCurrent, defaultPageSize)
+
+ const onChange = (current: number) => {
+   setList(current, defaultPageSize)
+ }
</script>

<template>
  <MyComponent />
  <ComponentDemo />
+   <List :data-source="dataList" />
+   <Pagination :default-current="defaultCurrent" :default-page-size="defaultPageSize" :total="total" @change="onChange" />
</template>

效果如下:

这里有几个需要注意的点:

  • 定义组件 props 的方式,组件函数只有一个唯一的 props 参数,可以定义 props 的类型,和定义 TypeScript 类型一样
export function Pagination(props: {
  defaultCurrent: number,
  defaultPageSize: number,
  total: number,
}) {
 ...
}
  • 定义 emit 的方式,通过 vineEmits 宏而不是 defineEmits 宏进行定义
const emit = vineEmits<{
  change: [current: number]
}>()

emit('change', current.value)

更多用法参考 Vue Vine 官网:https://vue-vine.dev/

你觉得 Vue Vine 风格写 Vue 组件体验如何呢?欢迎在评论区留言讨论。

联系我们

GitHub:https://github.com/opentiny/tiny-vue(欢迎 Star ⭐)

官网:https://opentiny.design/tiny-vue

B站:https://space.bilibili.com/15284299

个人博客:https://kagol.github.io/blogs

小助手微信:opentiny-official

公众号:OpenTiny

From:https://www.cnblogs.com/kagol/p/18342296
本文地址: http://www.shuzixingkong.net/article/781
0评论
提交 加载更多评论
其他文章 英语.Net多语言开发中的问题
问题与现象 多语言开发是一件成本很高的事情。 很多公司会退而求其次选择只开发英文版本的软件分发到不同国家,但这里仍存在不同问题。 我们就遇到了这样的问题,参考下面的代码。 CultureInfo&#160;culture;double&#160;number&#160;=1.5; culture&#
程序员副业探索之电商
在腾讯广告工作期间,我主要负责小程序电商与广告业务,见证了互联网电商行业的剧变,特别是众多电商公司纷纷拥抱私域流量,直播带货成为新风尚,广告投入也在持续增加。通过这些经历,我积累了不少关于互联网电商的经验,并萌生了尝试电商副业的想法。 在小红书上,女装博主们凭借独特的穿搭分享吸引了大量粉丝,“种草”
程序员副业探索之电商 程序员副业探索之电商 程序员副业探索之电商
全双工网卡在实际工作中上下行的网速速率是否一致?千兆网卡的同时上下行速率上限是否一样,网卡速率是上下行之和还是分别等于上下行速率
一直有个问题,就是理论上全双工网卡在运行时上下行的上限速率应该是一致的,但是实际网卡的标识的最高速率是否是指上下行速率之和还是和上下行速率一样。 为了解决这个问题,于是拿了两台台式机,分别装有千兆网卡(全双工),并使用六类线网线,两台主机同时向对方拷贝文件,效果如下: 结论: 全双工的网卡,其上下行
全双工网卡在实际工作中上下行的网速速率是否一致?千兆网卡的同时上下行速率上限是否一样,网卡速率是上下行之和还是分别等于上下行速率 全双工网卡在实际工作中上下行的网速速率是否一致?千兆网卡的同时上下行速率上限是否一样,网卡速率是上下行之和还是分别等于上下行速率
使用django-treebeard实现树类型存储与编辑
前言 其实之前做很多项目都有遇到跟树相关的功能,以前都是自己实现的,然后前端很多UI组件库都有Tree组件,套上去就可以用。 不过既然用 Django 了,还是得充分发挥一下生态的优势,但是我找了半天,也就这个 treebeard 能用,其他要不停更了要不就功能很拉,没有可视化编辑树的功能。 难道D
使用django-treebeard实现树类型存储与编辑
从零体检一个魔塔社区模型(modelscope)最简单demo
从社区拿一个模型,比如以下这个链接 https://www.modelscope.cn/models/iic/cv_mobilenet-v2_bad-image-detecting 它的代码样例如下 from modelscope.pipelines import pipeline from mod
从零体检一个魔塔社区模型(modelscope)最简单demo 从零体检一个魔塔社区模型(modelscope)最简单demo
【EF Core】自动生成的字段值
自动生成字段值,咱们首先想到的是主键列(带 IDENTITY 的主键)。EF Core 默认的主键配置也是启用 Identity 自增长的,而且可以自动标识主键。前提是代表主键的实体属性名要符合以下规则: 1、名字叫 ID、id、或 Id,就是不分大小写; 2、名字由实体类名 + Id 构成。比如,
【EF Core】自动生成的字段值 【EF Core】自动生成的字段值
实现一个终端文本编辑器来学习golang语言:第三章文本查看器part1
本章我们来完成文本编辑器的文件打开和查看功能,最后成品如上图。我们将分4步,逐渐完成本章所需功能。内容比较多,会分为两个部分,第一部分主要关注于“View视图”和“buffer及文本读取”。 如上图最终效果所示,我们希望在终端的最下方增加一个状态栏,能够展示当前被打开的文件和当前的光标位置。 同时我
实现一个终端文本编辑器来学习golang语言:第三章文本查看器part1 实现一个终端文本编辑器来学习golang语言:第三章文本查看器part1
PowerBI_一分钟学会利用ALLEXCPET分组计算(以计算门店开业前3天销售金额为例)
在某些特殊场景,我们往往需要去计算一些特定的组别的聚合数据 今天,就以计算门店开业前3天的销售情况,来学习一下,利用计算列和DAX度量值,两种快捷计算此类问题的方案。 一:XMIND 二:示例数据 2.1 示例数据列说明 为了方便验证和更清晰的检查结果,数据源只用了三列,分别是3个门店,分别为A,B
PowerBI_一分钟学会利用ALLEXCPET分组计算(以计算门店开业前3天销售金额为例) PowerBI_一分钟学会利用ALLEXCPET分组计算(以计算门店开业前3天销售金额为例) PowerBI_一分钟学会利用ALLEXCPET分组计算(以计算门店开业前3天销售金额为例)