Vue 3 组件语法知识点与案例代码

Vue 3 是一个用于构建用户界面的渐进式 JavaScript 框架。Vue 3 引入了许多新特性和改进,使得开发更加高效和灵活。以下是 Vue 3 组件的全面语法知识点以及一个详细的案例代码,带有详细注释,帮助初学者快速上手。

组件核心概念

  • 单文件组件(SFC).vue 文件,包含模板、脚本和样式
  • 组件选项data, methods, computed, props, emits
  • 生命周期钩子onMounted, onUpdated, onUnmounted
  • 组合式APIsetup() 函数,ref, reactive
  • 组件通信props 向下传递,emits 向上触发

一、Vue 3 组件语法知识点

1. 创建 Vue 应用

使用 createApp 方法创建一个新的 Vue 应用实例。

import { createApp } from 'vue';
import App from './App.vue';

createApp(App).mount('#app');

2. 组件基础

一个 Vue 组件通常由三个部分组成:模板(Template)、脚本(Script)和样式(Style)。

<template>
  <div>{{ message }}</div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello, Vue 3!'
    };
  }
};
</script>

<style scoped>
div {
  color: blue;
}
</style>

3. 使用组合式 API(Composition API)

组合式 API 提供了更灵活的逻辑复用方式,主要通过 setup 函数和 ref, reactive 等函数实现。

import { ref, reactive } from 'vue';

export default {
  setup() {
    const count = ref(0);
    const state = reactive({ message: 'Hello' });

    function increment() {
      count.value++;
    }

    return {
      count,
      state,
      increment
    };
  }
};

4. 生命周期钩子

Vue 3 提供了多个生命周期钩子,如 onMounted, onUpdated, onUnmounted 等,用于在组件的不同阶段执行代码。

import { onMounted, onUpdated, onUnmounted } from 'vue';

export default {
  setup() {
    onMounted(() => {
      console.log('组件已挂载');
    });

    onUpdated(() => {
      console.log('组件已更新');
    });

    onUnmounted(() => {
      console.log('组件已卸载');
    });
  }
};

5. 组件通信

5.1 Props 和 Emits

通过 props 接收父组件传递的数据,通过 emits 触发自定义事件向父组件传递数据。

<!-- ChildComponent.vue -->
<template>
  <button @click="notifyParent">点击我</button>
</template>

<script>
export default {
  props: {
    title: {
      type: String,
      required: true
    }
  },
  emits: ['notify'],
  methods: {
    notifyParent() {
      this.$emit('notify', '来自子组件的消息');
    }
  }
};
</script>
<!-- ParentComponent.vue -->
<template>
  <ChildComponent :title="parentTitle" @notify="handleNotify" />
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: { ChildComponent },
  data() {
    return {
      parentTitle: '父组件标题'
    };
  },
  methods: {
    handleNotify(message) {
      console.log(message);
    }
  }
};
</script>
5.2 Provide 和 Inject

provideinject 用于祖先组件向后代组件传递数据,而无需通过 props 逐层传递。

// AncestorComponent.vue
export default {
  setup() {
    const sharedData = ref('共享数据');
    provide('shared', sharedData);
  }
};
// DescendantComponent.vue
import { inject } from 'vue';

export default {
  setup() {
    const sharedData = inject('shared');
    return { sharedData };
  }
};

6. 插槽(Slots)

插槽允许在组件中插入任意模板内容。

<!-- MyButton.vue -->
<template>
  <button class="my-button">
    <slot></slot>
  </button>
</template>

<style scoped>
.my-button {
  padding: 10px 20px;
  background-color: #42b983;
  color: white;
  border: none;
  border-radius: 5px;
}
</style>
<!-- ParentComponent.vue -->
<template>
  <MyButton>
    <span>点击我</span>
  </MyButton>
</template>

<script>
import MyButton from './MyButton.vue';

export default {
  components: { MyButton }
};
</script>

7. Teleport 组件

Teleport 允许将组件的模板内容渲染到 DOM 结构中的其他位置。

<!-- TeleportComponent.vue -->
<template>
  <button @click="showModal = true">打开模态框</button>
  <Teleport to="body">
    <div v-if="showModal" class="modal">
      <p>这是一个模态框</p>
      <button @click="showModal = false">关闭</button>
    </div>
  </Teleport>
</template>

<script>
import { ref } from 'vue';

export default {
  setup() {
    const showModal = ref(false);
    return { showModal };
  }
};
</script>

<style scoped>
.modal {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  padding: 20px;
  background-color: white;
  border: 1px solid #ccc;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
</style>

8. 过渡与动画

Vue 3 提供了 <transition><transition-group> 组件,用于实现元素进入和离开的过渡效果。

<!-- TransitionComponent.vue -->
<template>
  <button @click="show = !show">切换显示</button>
  <transition name="fade">
    <p v-if="show">Hello, Vue 3!</p>
  </transition>
</template>

<script>
import { ref } from 'vue';

export default {
  setup() {
    const show = ref(true);
    return { show };
  }
};
</script>

<style scoped>
.fade-enter-active, .fade-leave-active {
  transition: opacity 0.5s;
}
.fade-enter-from, .fade-leave-to {
  opacity: 0;
}
.fade-enter-to, .fade-leave-from {
  opacity: 1;
}
</style>

9. 自定义指令

可以通过自定义指令来扩展 Vue 的功能。

// focusDirective.js
export default {
  mounted(el) {
    el.focus();
  }
};
<!-- 使用自定义指令 -->
<template>
  <input v-focus />
</template>

<script>
import focusDirective from './focusDirective.js';

export default {
  directives: {
    focus: focusDirective
  }
};
</script>

10. 插件

插件用于为 Vue 添加全局功能,如全局指令、混入等。

// myPlugin.js
export default {
  install(app, options) {
    app.directive('focus', {
      mounted(el) {
        el.focus();
      }
    });

    app.mixin({
      created() {
        console.log('全局混入');
      }
    });
  }
};
// main.js
import { createApp } from 'vue';
import App from './App.vue';
import myPlugin from './myPlugin.js';

const app = createApp(App);
app.use(myPlugin);
app.mount('#app');

二、案例代码

以下是一个简单的 Vue 3 应用示例,包含导航栏、主内容区和侧边栏组件,使用组合式 API 和组件通信实现。代码中包含详细注释,帮助理解每个部分的功能。

<!-- App.vue -->
<template>
  <div id="app">
    <Header :title="appTitle" @toggle-sidebar="toggleSidebar" />
    <div class="container">
      <Sidebar :isVisible="isSidebarVisible" @close="toggleSidebar" />
      <MainContent />
    </div>
  </div>
</template>

<script>
import { ref } from 'vue';
import Header from './components/Header.vue';
import Sidebar from './components/Sidebar.vue';
import MainContent from './components/MainContent.vue';

export default {
  name: 'App',
  components: {
    Header,
    Sidebar,
    MainContent
  },
  setup() {
    const isSidebarVisible = ref(false);
    const appTitle = '我的 Vue 3 应用';

    function toggleSidebar() {
      isSidebarVisible.value = !isSidebarVisible.value;
    }

    return {
      isSidebarVisible,
      appTitle,
      toggleSidebar
    };
  }
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  text-align: center;
  color: #2c3e50;
}

.container {
  display: flex;
  min-height: 100vh;
}

@media (max-width: 768px) {
  .container {
    flex-direction: column;
  }
}
</style>
<!-- components/Header.vue -->
<template>
  <header class="header">
    <h1>{{ title }}</h1>
    <button @click="emitToggle">侧边栏</button>
  </header>
</template>

<script>
import { ref } from 'vue';

export default {
  name: 'Header',
  props: {
    title: {
      type: String,
      required: true
    }
  },
  emits: ['toggle-sidebar'],
  setup(props, { emit }) {
    function emitToggle() {
      emit('toggle-sidebar');
    }

    return {
      emitToggle
    };
  }
};
</script>

<style scoped>
.header {
  background-color: #42b983;
  padding: 20px;
  color: white;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
</style>
<!-- components/Sidebar.vue -->
<template>
  <div v-if="isVisible" class="sidebar">
    <h2>侧边栏</h2>
    <ul>
      <li><a href="#">首页</a></li>
      <li><a href="#">关于</a></li>
      <li><a href="#">联系</a></li>
    </ul>
    <button @click="close">关闭</button>
  </div>
</template>

<script>
import { ref } from 'vue';

export default {
  name: 'Sidebar',
  props: {
    isVisible: {
      type: Boolean,
      required: true
    }
  },
  emits: ['close'],
  setup(props, { emit }) {
    function close() {
      emit('close');
    }

    return {
      close
    };
  }
};
</script>

<style scoped>
.sidebar {
  background-color: #f4f4f4;
  padding: 20px;
  width: 200px;
  border-right: 1px solid #ccc;
}
.sidebar ul {
  list-style: none;
  padding: 0;
}
.sidebar li {
  margin: 10px 0;
}
.sidebar a {
  text-decoration: none;
  color: #2c3e50;
}
.sidebar button {
  margin-top: 20px;
  padding: 10px 15px;
  background-color: #42b983;
  color: white;
  border: none;
  border-radius: 5px;
  cursor: pointer;
}
</style>
<!-- components/MainContent.vue -->
<template>
  <main class="main-content">
    <h1>欢迎来到我的 Vue 3 应用</h1>
    <p>这是一个使用 Vue 3 构建的简单示例应用。</p>
  </main>
</template>

<script>
export default {
  name: 'MainContent'
};
</script>

<style scoped>
.main-content {
  padding: 20px;
  flex-grow: 1;
}
</style>

代码说明

  1. App.vue

    • 使用组合式 API 管理侧边栏的显示状态。
    • 通过 props 将标题传递给 Header 组件,并通过 emit 触发 toggle-sidebar 事件。
    • 使用 Sidebar 组件并通过 props 控制其显示状态。
    • 使用 MainContent 组件显示主内容。
  2. Header.vue

    • 显示应用标题和一个按钮,用于切换侧边栏的显示。
    • 使用 emit 触发 toggle-sidebar 事件,向父组件传递事件。
  3. Sidebar.vue

    • 根据 isVisible 状态显示或隐藏侧边栏。
    • 显示侧边栏内容和关闭按钮,并通过 emit 触发 close 事件,向父组件传递关闭事件。
  4. MainContent.vue

    • 显示主内容区域,包含一个标题和一段文本。
  5. 样式

    • 使用 scoped 样式,确保样式仅作用于当前组件。
    • 使用 Flexbox 实现布局的响应式设计。

运行效果

该案例展示了一个简单的 Vue 3 应用,包含导航栏、主内容区和侧边栏。通过点击导航栏的按钮,可以显示或隐藏侧边栏。布局在不同屏幕尺寸下具有响应性,适应不同的设备。

三、总结

Vue 3 提供了丰富的组件语法和强大的功能,使得构建复杂的用户界面变得更加容易。通过掌握上述语法知识点,并结合实际案例进行练习,可以帮助初学者快速掌握 Vue 3 的使用方法。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐