Skip to content

Vue 3 Integration Guide

This guide will help you integrate Vant with Vue 3 projects, covering new features, best practices, and optimization strategies.

Vue 3 New Features Support

Composition API Integration

Vant fully supports Vue 3's Composition API, allowing you to use components in a more flexible way:

vue
<template>
  <van-button @click="handleClick">{{ buttonText }}</van-button>
  <van-field v-model="inputValue" placeholder="Please enter" />
</template>

<script setup>
import { ref, computed } from 'vue'
import { Button, Field } from 'vant'

const inputValue = ref('')
const buttonText = computed(() => 
  inputValue.value ? `Input: ${inputValue.value}` : 'Click me'
)

const handleClick = () => {
  console.log('Button clicked:', inputValue.value)
}
</script>

Reactive System Deep Integration

Leverage Vue 3's reactive system for better performance:

javascript
import { reactive, watch } from 'vue'
import { Toast } from 'vant'

const state = reactive({
  loading: false,
  data: []
})

// Watch reactive data
watch(() => state.loading, (newVal) => {
  if (newVal) {
    Toast.loading('Loading...')
  } else {
    Toast.clear()
  }
})

TypeScript Perfect Support

Component Type Definitions

Vant provides complete TypeScript type definitions:

typescript
import type { ButtonType, ButtonSize } from 'vant'

interface ButtonConfig {
  type: ButtonType
  size: ButtonSize
  loading: boolean
}

const buttonConfig: ButtonConfig = {
  type: 'primary',
  size: 'large',
  loading: false
}

Event Type Safety

Get full type safety for component events:

vue
<script setup lang="ts">
import { Button } from 'vant'
import type { MouseEvent } from 'vue'

const handleClick = (event: MouseEvent) => {
  console.log('Click event:', event)
}
</script>

<template>
  <van-button @click="handleClick">Click me</van-button>
</template>

Performance Optimization Strategies

Tree Shaking

Vue 3 + Vant supports better tree shaking:

javascript
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  build: {
    rollupOptions: {
      external: ['vue'],
      output: {
        manualChunks: {
          'vant-components': ['vant']
        }
      }
    }
  }
})

Component Lazy Loading

Use Vue 3's defineAsyncComponent for lazy loading:

javascript
import { defineAsyncComponent } from 'vue'

const LazyComponent = defineAsyncComponent(() =>
  import('./components/HeavyComponent.vue')
)

Teleport Integration

Combine Vant components with Vue 3's Teleport:

vue
<template>
  <teleport to="body">
    <van-overlay :show="showOverlay">
      <van-loading />
    </van-overlay>
  </teleport>
</template>

Theme Customization & Styling

CSS Variables Integration

Use Vue 3's style binding with Vant's CSS variables:

vue
<template>
  <div :style="themeVars">
    <van-button type="primary">Themed Button</van-button>
  </div>
</template>

<script setup>
import { computed } from 'vue'

const props = defineProps(['primaryColor'])

const themeVars = computed(() => ({
  '--van-primary-color': props.primaryColor || '#1989fa'
}))
</script>

Dynamic Theme Switching

Implement dynamic theme switching:

javascript
import { ref, watchEffect } from 'vue'

const isDark = ref(false)

watchEffect(() => {
  document.documentElement.setAttribute(
    'data-theme', 
    isDark.value ? 'dark' : 'light'
  )
})

// CSS
// [data-theme="dark"] {
//   --van-primary-color: #4fc3f7;
//   --van-background-color: #121212;
// }

Best Practices

1. Component Organization

Organize Vant components efficiently:

javascript
// composables/useVant.js
import { 
  Button, 
  Field, 
  Form, 
  Toast,
  Dialog 
} from 'vant'

export function useVantComponents() {
  return {
    Button,
    Field,
    Form,
    Toast,
    Dialog
  }
}

2. Global Configuration

Set up global configurations:

javascript
// main.js
import { createApp } from 'vue'
import { ConfigProvider } from 'vant'
import App from './App.vue'

const app = createApp(App)

app.use(ConfigProvider, {
  theme: 'light',
  themeVars: {
    primaryColor: '#1989fa'
  }
})

3. Form Handling

Leverage Vue 3's form handling capabilities:

vue
<template>
  <van-form @submit="onSubmit">
    <van-field
      v-model="form.username"
      name="username"
      label="Username"
      placeholder="Username"
      :rules="[{ required: true, message: 'Please enter username' }]"
    />
    <van-field
      v-model="form.password"
      type="password"
      name="password"
      label="Password"
      placeholder="Password"
      :rules="[{ required: true, message: 'Please enter password' }]"
    />
    <div style="margin: 16px;">
      <van-button round block type="primary" native-type="submit">
        Submit
      </van-button>
    </div>
  </van-form>
</template>

<script setup>
import { reactive } from 'vue'
import { Toast } from 'vant'

const form = reactive({
  username: '',
  password: ''
})

const onSubmit = (values) => {
  console.log('submit', values)
  Toast.success('Submit success')
}
</script>

4. State Management Integration

Integrate with Pinia (Vue 3's recommended state management):

javascript
// stores/app.js
import { defineStore } from 'pinia'
import { Toast } from 'vant'

export const useAppStore = defineStore('app', {
  state: () => ({
    loading: false,
    theme: 'light'
  }),
  
  actions: {
    setLoading(loading) {
      this.loading = loading
      if (loading) {
        Toast.loading('Loading...')
      } else {
        Toast.clear()
      }
    },
    
    toggleTheme() {
      this.theme = this.theme === 'light' ? 'dark' : 'light'
    }
  }
})

Migration from Vue 2

Key Differences

  1. Global API Changes: Use createApp instead of new Vue
  2. Component Registration: Use app.component() for global registration
  3. Event Handling: Some event names have changed
  4. Lifecycle Hooks: Use Composition API lifecycle hooks

Migration Example

Vue 2 style:

javascript
// Vue 2
import Vue from 'vue'
import { Button } from 'vant'

Vue.use(Button)

new Vue({
  data() {
    return {
      count: 0
    }
  },
  methods: {
    increment() {
      this.count++
    }
  }
})

Vue 3 style:

javascript
// Vue 3
import { createApp, ref } from 'vue'
import { Button } from 'vant'

const app = createApp({
  setup() {
    const count = ref(0)
    
    const increment = () => {
      count.value++
    }
    
    return {
      count,
      increment
    }
  }
})

app.use(Button)
app.mount('#app')

Common Issues and Solutions

1. SSR Support

For server-side rendering with Nuxt 3:

javascript
// nuxt.config.ts
export default defineNuxtConfig({
  css: ['vant/lib/index.css'],
  build: {
    transpile: ['vant']
  }
})

2. Vite Configuration

Optimize Vite configuration for Vant:

javascript
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  optimizeDeps: {
    include: ['vant']
  }
})

3. Testing Setup

Set up testing with Vue Test Utils:

javascript
// test setup
import { mount } from '@vue/test-utils'
import { Button } from 'vant'

const wrapper = mount(Button, {
  props: {
    type: 'primary'
  }
})

expect(wrapper.classes()).toContain('van-button--primary')

Conclusion

Vue 3 + Vant provides a powerful combination for building modern mobile applications. By following these best practices and leveraging Vue 3's new features, you can create efficient, maintainable, and performant applications.

For more detailed information, please refer to:

Enterprise-level mobile solution based on Vant