Vue-组合式API
vite构建工具
搭建vue3项目
npm create vite
cd dir-vite
: 进入项目目录npm install
: 安装依赖npm run dev
: 启动项目
Local: http://localhost:5173/ Network: use --host to expose Vue DevTools: Open http://localhost:5173/__devtools__/ as a separate window Vue DevTools: Press Alt+Shift+D in App to toggle the Vue DevTools
启动过程
- 启动服务
当执行npm run dev
时, 使用了vite
工具启动了一个调试服务器(dev Server). 监听5173
端口.- 会将
vite-vue
作为网站的根目录
- 会将
index.html
作为网站的默认文件
- 当浏览器访问
localhost:5173
时, 调试服务器会将index.html
返回给浏览器
- 会将
- 加载
main.js
- 在
index.html
中, 加载了main.js
- 在
main.js
导入App组件
- 在
单文件组件
一个.vue
文件就是一个单文件组件, 包括
- template: 模板, 用于编写
HTML
- script: 逻辑, 用于编写
JS
- style: 样式, 用于编写
CSS
<template> <!-- 组件的模板部分 --> 计数器:{{ count }} <button @click="handleClick">点击+1</button> </template> <script setup> import { ref } from 'vue' const count = ref(0) function handleClick() { count.value++ } </script> <style> /* 组件的样式 */ </style>
组合式API
setup语法糖
在vue
项目中, 通常使用setup
语法简化书写
- 在setup语法中定义变量, 可以直接在模板中使用
- 在setup语法中定义函数, 可以直接在模板中使用
- 导入的组件对象, 可以直接在模板中使用
常用的组合式API
- ref
- computed
- watch
- onMounted
ref
响应性 API,用于创建一个响应式的数据源ref
对象, ref
对象具有一个指向内部值的 .value
属性。
import { ref } from 'vue' // 声明变量 const count = ref(0); // 使用变量, 需要通过.value属性来访问 console.log(count.value); // 输出 0 // 在 setup 函数中返回 ref export default { setup() { const count = ref(0); return { count }; } };
<template> <button @click="handleClick">显示/隐藏</button> <div v-show="flag">这是一个div</div> </template> <script setup> import { ref } from 'vue' // 声明变量 const flag = ref(true) // 声明函数 function handleClick() { flag.value = !flag.value } </script>
computed
<template> 姓: <input type="text" v-model="firstname" /> <br /> 名: <input type="text" v-model="lastname" /> <br /> 全名: {{ fullname }} </template> <script setup> import { computed, ref } from 'vue' const firstname = ref('') const lastname = ref('') const fullname = computed(() => { return firstname.value + lastname.value }) </script>
创建可读写的计算属性:
const doubleCount = computed({ get: () => { return count.value * 2; }, set: (newValue) => { count.value = newValue / 2; } });
watch
<template> 单价: 5 <br /> 数量: <input type="text" v-model.number="num" /> <br /> 总价: {{ total }} </template> <script setup> import { ref, watch } from 'vue' const num = ref(0) const total = ref(0) watch(num, () => { total.value = num.value * 5 }) </script>
onMounted
生命周期钩子函数,用于在组件挂载(即元素被插入到 DOM 中)之后执行代码。这是执行副作用操作(如设置定时器、发起网络请求、直接操作 DOM 等)的理想时机。
<template> <ul> <li v-for="book in books" :key="book.id">{{ book.name }}</li> </ul> </template> <script setup> import { onMounted, ref } from 'vue' const books = ref([]) onMounted(() => { // 在onMounted中给books赋值 setTimeout(() => { books.value = [ { id: 1, name: 'vue' }, { id: 2, name: 'gis' }, { id: 3, name: 'js' }, ] }, 1000) }) </script>
组件
简单使用
- 定义组件
在components
目录下, 创建组件文件TheCounter.vue
<template> 计数器:{{ count }} <button @click="handleClick">点击+1</button> </template> <script setup> import { ref } from 'vue' const count = ref(0) console.log(count) function handleClick() { count.value++ } </script> <style> /* 组件的样式 */ </style>
- 导入组件
在App.vue
中, 通过import
语法导入组件对象
<script setup> // 2. 导入组件对象 import TheCounter from './components/TheCounter.vue' </script>
- 引用组件
在App.vue
的模板中, 通过组件名
引用组件
<template> <!-- 3. 引用组件 --> <TheCounter></TheCounter> </template>
父传子
父组件向子组件传递数据
- 在父组件中, 借助自定义属性
- 在子组件中, 通过
defineProps
接受
defineProps
- 只能在
<script setup>
的顶层使用 type
:String
、Number
、Boolean
、Array
、Object
、Date
default
: 默认值required: true
,指定一个属性是必需的validator
,用于自定义验证函数
静态绑定
<template> <TheBlog title="01-vue"></TheBlog> <TheBlog title="02-gis"></TheBlog> <TheBlog title="03-js"></TheBlog> </template> <script setup> import TheBlog from './components/TheBlog.vue' </script>
<template> <div>{{ title }}</div> </template> <script setup> const props = defineProps({ title: { type: String, required: true, }, }) </script>
动态绑定
<template> <TheBlog title="01-vue"></TheBlog> <TheBlog title="02-gis"></TheBlog> <!-- 将属性值和App组件中的一个状态动态绑定 --> <TheBlog :title="t"></TheBlog> </template> <script setup> import TheBlog from './components/TheBlog.vue' import { ref } from 'vue' const t = ref('03-标题') </script>
子传父
子组件向父组件传递数据
- 在子组件中, 触发自定义事件
- 在父组件中, 监听自定义事件, 在回调函数中通过参数获取
自定义事件
const emit = defineEmits(['eventName1', 'eventName2']);
<script setup> const emit = defineEmits({ eventName1: null, // 不进行类型检查 eventName2: (payload) => { // 类型检查函数 if (typeof payload !== 'string') { console.warn('eventName2 expects a string as the payload'); } } }); </script>
<template> <button @click="updateValue(newvalue)">更新值</button> </template> <script setup> import { ref } from 'vue'; const newvalue = ref('新值') const emit = defineEmits(['childclick']); function updateValue(newValue) { emit('childclick', newValue); } </script>
<template> <ChildComponent @childclick="handleChildClick($event)" /> <p>当前值: {{ modelValue }}</p> </template> <script setup> import { ref } from 'vue'; import ChildComponent from './components/test.vue'; const modelValue = ref('初始值'); function handleChildClick(value) { modelValue.value = value } </script>
实例: 根据id关闭指定组件
<template> <div> {{ title }} <button @click="handleClick">关闭</button> </div> </template> <script setup> const props = defineProps({ title: { type: String, required: true, }, id: { type: Number, required: true, }, }) const emits = defineEmits(['close']) function handleClick() { emits('close', props.id) } </script>
<template> <!-- v-if和v-for不能应用于同一个元素 --> <TheBlog v-for="blog in showBlogs" :key="blog.id" :title="blog.title" :id="blog.id" @close="handleClose" ></TheBlog> </template> <script setup> import TheBlog from './components/test.vue' import { ref, computed } from 'vue' const blogs = ref([ { id: 1, title: '01-vue', isShow: true }, { id: 2, title: '02-gis', isShow: true }, { id: 3, title: '03-mapbox', isShow: true }, ]) const showBlogs = computed(() => { return blogs.value.filter((item) => item.isShow) }) function handleClose(id) { console.log(id) const blog = blogs.value.find((item) => item.id == id) blog.isShow = false } </script>
provide和inject
- provide: 提供. 数据由祖先组件提供
- inject: 注入. 由后代组件获取数据
在app
应用实例上挂载
const app = createApp(App) // 通过app定义全局的对象: $map app.provide('$map', { map: 'world' })
在app
对应的子组件中, 可以直接引用
import { inject } from 'vue' const map = inject('$map') console.log(map)
插槽
- 在组件中预留一个
slot
插槽 - 在组件渲染时, 将内容
插入
到slot
中
普通插槽
在子组件定时时, 预留插槽
<template> <!-- 预留一个slot插槽 --> <slot></slot> </template>
在渲染子组件时, 会使用组件内部的内容替换掉slot部分
<TheComputer> <div> <h3>名称: MacBookPro</h3> <p>型号: MBP 14 M1</p> </div> </TheComputer>
具名插槽
在定义slot
插槽时, 设置name
属性
<template> <!-- 具名插槽 --> <slot name="cpu"></slot> <slot name="memery"></slot> </template>
在渲染时, 通过v-slot
指令指定插槽的名称
<template> <TheComputer> <template v-slot:cpu> <!-- 这里的内容插入到名字叫cpu的插槽中 --> CPU: M1 Pro </template> <template #memery> Memery: 16G </template> </TheComputer> </template>
作用域插槽
将子组件的属性及其值传递给父组件,以便在父组件的插槽内容中使用
- 默认插槽
<template> <div> <slot :userprop="user"></slot> </div> </template> <script setup> const user = reactive({ name: '张三', age: 30}) </script>
<template> <test> <template v-slot:default="slotProps"> {{ slotProps.userprop.name }} - {{ slotProps.userprop.age }} </template> </test> </template>
- 具名插槽
<template> <div> <slot name="body" msg="这是消息" :age="12"></slot> </div> </template>
<template> <test> <template #body="data"> 这是插槽内部传递的数据: {{ data.msg }} age: {{ data.age }} </template> </test> </template>
本文作者:Khru
本文链接:https://www.cnblogs.com/khrushchefox/p/18573277
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步