Location>code7788 >text

Vue Vine: A new way to write Vue!

Popularity:807 ℃/2024-08-04 22:13:27

Hello, I'm Kagol, personal public:Front-end open source planet

Last month andTinyVue We attended VueConf 24 together and had the honor of meeting Mr. Shen Qingchuan and learning about hisVue Vine project, Vue Vine lets you define multiple Vue components in a single file by way of functions, while having access to all of Vue's templating features.

Doesn't that sound cool!

I've written about SFC before, and I've also written about Vue components for JSX, and they both have their drawbacks.

  • SFC as the name suggests single file components, can only define a component in a file, if there are several related components want to put together, sorry, can not! You can only create a folder and put a bunch of related components in it one file at a time.
  • JSX can define components as functions and define multiple related components in a single file, but it doesn't have the benefit of Vue's template syntax and optimizations related to template compilation.

Vue Vine creates a new way of writing Vue components by bringing the best of both worlds together.

Let's experience it together!

Building a Vue Vine Environment

Let's say you already have a Vite + Vue3 project.

Only the following steps are required to set up a Vue Vine environment:

  • Install the vue-vine dependency:npm i -D vue-vine
  • exist embedded inVineVitePlugin plug-in (software component)
import { VineVitePlugin } from 'vue-vine/vite'

export default defineConfig({
  plugins: [
    // ... Other plugins
    VineVitePlugin()
  ]
})
  • Installing the VSCode extension: Vue Vine

  • exist Configure the macro type in
{
  "compilerOptions": {
    "types": ["vue-vine/macros"]
  }
}

Have fun with Vue Vine!

We create a file, write the following:

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

Then introduce the component in the

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

<template>
  <MyComponent />
</template>

You can see that the display shows aHello World

Define another component and bring in a TinyVue component to try it out.

file, write the following:

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

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

+ export function ComponentDemo() {
+ return vine`
+ <tiny-button type="primary">recognize</tiny-button>
+ <tiny-alert description="It's a description."></tiny-alert>
+ `
+ }

Introducing this component in the

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

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

Write a simple paging component using Vue Vine.

I've written about it before on my blog:Teach you to use Vue / React / Angular three major frameworks to develop Pagination paging components

We'll rewrite it the Vue Vine way now.

establish file, write the following:

import { ref } from 'vue'

// Demo Components props define
export function Pagination(props: {
  defaultCurrent: number,
  defaultPageSize: number,
  total: number,
}) {
  // demonstrations emit 事件define
  const emit = vineEmits<{
    change: [current: number]
  }>()

  // Current page number
  const current = ref()
  
  // Total page numbers
  const totalPage = ref(( / ))
  
  // 设置Current page number
  const setPage = (page: number) => {
    if (page < 1) return
    if (page > ) return
     = page
    emit('change', )
  }

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

// 自define Button subassemblies(demonstrations <slot></slot> slots)
export function Button() {
  const emit = vineEmits<{
    click: []
  }>()

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

Define another List component to simulate paging data.

import { ref, watch } from 'vue'

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

  watch(() => , (newVal) => {
     = newVal
  })

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

Use the Pagination and List components in.

<script setup lang="ts">
+ import { ref } from 'vue'
+ import chunk from 'lodash-es/chunk'
import { MyComponent, ComponentDemo } from './components/'
+ import { Pagination } from './'
+ import { List } from './'
+
+ // data sources
+ 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' },
+ ]
+
+ // List the currently displayed data
+ const dataList = ref<{
+ id: number
+ name: string
+ }[]>([])
+
+ const defaultCurrent = 1
+ const defaultPageSize = 3
+ const total =
+
+ // Setting the current list data
+ const setList = (current: number, pageSize: number) => {
+ = 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>

The effect is as follows:

Here are a couple of points to keep in mind:

  • The way to define component props, the component function has only one unique props parameter, and you can define the type of props in the same way as you define the TypeScript type.
export function Pagination(props: {
  defaultCurrent: number,
  defaultPageSize: number,
  total: number,
}) {
 ...
}
  • The way emits are defined is through the vineEmits macro instead of the defineEmits macro.
const emit = vineEmits<{
  change: [current: number]
}>()

emit('change', )

See the Vue Vine website for more usage:/

What do you think of the Vue Vine style experience for writing Vue components? Feel free to discuss in the comments section.

Contact Us

GitHub:/opentiny/tiny-vue(Welcome Star ⭐)

Official website:/tiny-vue

Station B:/15284299

Personal Blog:/blogs

Small assistant WeChat: opentiny-official

Public: OpenTiny