Skip to content

Vue 3 生命周期与数据绑定代码风格示例

Vue 3 生命周期钩子(Composition API 风格)

javascript
import {
    onBeforeMount,
    onMounted,
    onBeforeUpdate,
    onUpdated,
    onBeforeUnmount,
    onUnmounted,
    onActivated,
    onDeactivated
} from 'vue'

export default {
    setup() {
        // 初始化阶段(替代 created 和 beforeCreate)
        console.log('setup: 组件初始化阶段')

        // 挂载阶段
        onBeforeMount(() => {
            console.log('onBeforeMount: 挂载开始之前')
        })

        onMounted(() => {
            console.log('onMounted: 实例已挂载到DOM上')
        })

        // 更新阶段
        onBeforeUpdate(() => {
            console.log('onBeforeUpdate: 数据更新时调用')
        })

        onUpdated(() => {
            console.log('onUpdated: 数据更改导致的重新渲染完成')
        })

        // 卸载阶段
        onBeforeUnmount(() => {
            console.log('onBeforeUnmount: 实例卸载之前')
        })

        onUnmounted(() => {
            console.log('onUnmounted: 实例卸载后')
        })

        // keep-alive 相关
        onActivated(() => {
            console.log('onActivated: 被keep-alive缓存的组件激活时')
        })

        onDeactivated(() => {
            console.log('onDeactivated: 被keep-alive缓存的组件停用时')
        })

        return {}
    }
}

数据绑定示例(Composition API)

1. 响应式基础

html

<template>
    <div>
        <p>Count: {{ count }}</p>
        <button @click="increment">+1</button>

        <p>User: {{ user.name }}</p>
        <button @click="changeName">Change Name</button>
    </div>
</template>

<script>
    import {ref, reactive} from 'vue'

    export default {
        setup() {
            // 基本类型使用 ref
            const count = ref(0)

            // 对象类型使用 reactive
            const user = reactive({
                name: 'John',
                age: 30
            })

            function increment() {
                count.value++ // 注意 ref 需要通过 .value 访问
            }

            function changeName() {
                user.name = 'Jane' // reactive 对象直接修改属性
            }

            return {
                count,
                user,
                increment,
                changeName
            }
        }
    }
</script>

2. 计算属性和侦听器

html

<template>
    <div>
        <input v-model="firstName" placeholder="First name">
        <input v-model="lastName" placeholder="Last name">
        <p>Full name: {{ fullName }}</p>

        <input v-model="question" placeholder="Ask a question">
        <p>Answer: {{ answer }}</p>
    </div>
</template>

<script>
    import {ref, computed, watch} from 'vue'

    export default {
        setup() {
            const firstName = ref('')
            const lastName = ref('')
            const question = ref('')
            const answer = ref('')

            // 计算属性
            const fullName = computed(() => {
                return `${firstName.value} ${lastName.value}`.trim()
            })

            // 侦听器
            watch(question, (newQuestion, oldQuestion) => {
                if (newQuestion.includes('?')) {
                    getAnswer()
                }
            })

            async function getAnswer() {
                answer.value = 'Thinking...'
                try {
                    // 模拟异步请求
                    const res = await fetch('https://yesno.wtf/api')
                    const data = await res.json()
                    answer.value = data.answer
                } catch (error) {
                    answer.value = 'Error! Could not reach the API. ' + error
                }
            }

            return {
                firstName,
                lastName,
                fullName,
                question,
                answer
            }
        }
    }
</script>

3. 组件通信

父组件

html

<template>
    <ChildComponent
            :title="parentTitle"
            @child-event="handleChildEvent"
    />
</template>

<script>
    import {ref} from 'vue'
    import ChildComponent from './ChildComponent.vue'

    export default {
        components: {ChildComponent},
        setup() {
            const parentTitle = ref('Parent Title')

            function handleChildEvent(payload) {
                console.log('Received from child:', payload)
            }

            return {
                parentTitle,
                handleChildEvent
            }
        }
    }
</script>

子组件

html

<template>
    <div>
        <h2>{{ title }}</h2>
        <button @click="sendToParent">Send to Parent</button>
    </div>
</template>

<script>
    export default {
        props: {
            title: String
        },
        emits: ['child-event'], // 显式声明自定义事件
        setup(props, {emit}) {
            function sendToParent() {
                emit('child-event', {message: 'Hello from child!'})
            }

            return {
                sendToParent
            }
        }
    }
</script>

代码风格建议

  1. 组合式函数:将相关逻辑提取到独立的函数中

    javascript
    // useUser.js
    import { ref } from 'vue'
    
    export default function useUser() {
      const user = ref(null)
      
      function fetchUser(id) {
        // 获取用户逻辑
      }
      
      return {
        user,
        fetchUser
      }
    }
    
    // 在组件中使用
    import useUser from './useUser'
    
    export default {
      setup() {
        const { user, fetchUser } = useUser()
        
        return {
          user
        }
      }
    }
  2. 解构响应式对象:使用 toRefs 保持响应式

    javascript
    import { reactive, toRefs } from 'vue'
    
    export default {
      setup() {
        const state = reactive({
          count: 0,
          name: 'Vue 3'
        })
        
        return {
          ...toRefs(state) // 保持响应式
        }
      }
    }
  3. TypeScript 支持:为 props 和 emits 提供类型定义

    typescript
    import { defineComponent } from 'vue'
    
    export default defineComponent({
      props: {
        title: {
          type: String,
          required: true
        },
        count: {
          type: Number,
          default: 0
        }
      },
      emits: {
        'update:count': (value: number) => true,
        'reset': null
      }
    })
  4. 模板引用:使用 ref 获取 DOM 引用

    html
    <template>
      <input ref="inputRef">
    </template>
    
    <script>
    import { ref, onMounted } from 'vue'
    
    export default {
      setup() {
        const inputRef = ref(null)
        
        onMounted(() => {
          inputRef.value.focus()
        })
        
        return {
          inputRef
        }
      }
    }
    </script>
  5. 样式作用域:使用 <style scoped>

    html
    <style scoped>
    .example {
      color: red;
    }
    </style>

Vue 3 的组合式 API 提供了更灵活的逻辑组织和复用方式,建议根据项目复杂度选择合适的 API 风格。对于简单组件,Options API 仍然是一个不错的选择;对于复杂逻辑,Composition API 能提供更好的代码组织和复用性。

✨ 网站运行时间: 3年11月15天 ❤️ 道阻且长,行则将至 - 微信号: heikedreamer