vue3基本使用&setup script语法糖&vue3中如何实现sync修饰符功能&`defineEmits` is a compiler macro and no longer needs to
vue3使用回顾/总结经验使你在第二次犯相同错误时及时发现。 —— 琼斯一、基本使用vue3.x组件开发のsetup和defineComponent1.1 defineComponent- 需要导入再使用。(使用ts需借助自动推导)- defineComponent 返回传递给它的对象或有一个有合成类型的构造函数。用于类型推导,简化类型定义。- 只要是vue本身API(比如setup或vue2.x
vue3使用回顾/总结
经验使你在第二次犯相同错误时及时发现。 —— 琼斯
一、基本使用
1. vue3.x组件开发のsetup和defineComponent
1.1 defineComponent
- 需要导入再使用。(使用ts需借助自动推导)
- defineComponent 返回传递给它的对象或有一个有合成类型的构造函数。用于类型推导,简化类型定义。
- 只要是vue本身API(比如setup或vue2.x的配置项),defineComponent 都可以自动推导。在编写组件中,只需维护自定义的数据类型,专注于业务。
- 参数:[ 具有组件选项的对象 | setup函数]
// 栗子
import { defineComponent } from 'vue'
// vue2.x 配置项
export default defineComponent({
data() {
return { count: 1 }
},
methods: {
increment() {
this.count++
}
}
})
// vue3
export default defineComponent({
setup (props, context) {
// ...
return {
// ...template 中用到的业务数据
}
}
})
// 参数为 setup函数 --- 备忘
const HelloWorld = defineComponent(function HelloWorld () {
return {
// ...template 中用到的业务数据
}
})
1.2 setup函数
- 一个组件选项,创建组件前执行,作为入口点
3.x中,整个组件相关的业务代码,都可放到 setup 里编写。因为setup后其他的生命周期才会被启用
- 参数(props,context)
props :它是响应式的(只要不解构它,或者使用 toRef / toRefs 进行响应式解构),当传入新的 prop 时,它将被更新。
context :一个普通的对象,它暴露三个组件的 property(attrs, slots, emit)
2. 生命周期
2.1 生命周期对比(Vue3.x compares with Vue2.x)
官方解释: “setup 是围绕 beforeCreate 和 created 生命周期钩子运行”
3.x中用setup的周期可以替代2.x版本中的beforeCreate和created的两个钩子
2.2 vue3.x的生命周期使用
3.x中,生命周期必须先导入再使用的,且必需放setup中执行
3. vue3新语法糖——setup script
3.1 使用方法
<script setup></script>
3.2 作用
- 自动注册子组件
(1) vue2.x语法
<template>
<div>
<h2>父组件!</h2>
<Child />
</div>
</template>
<script>
import Child from './Child.vue'
export default {
component: {
Child // 注册子组件后方可在template中使用
}
}
</script>
(2)vue3语法
<template>
<div>
<h2>父组件!</h2>
<Child />
</div>
</template>
<script>
import { defineComponent, ref } from 'vue';
import Child from './Child.vue'
export default defineComponent({
components: {
Child // 注册子组件后方可在template中使用
},
setup() {
return {
}
}
});
</script>
(3)setup script语法
<template>
<div>
<h2>父组件!-setup script</h2>
<Child />
</div>
</template>
<script setup>
import Child from './Child.vue'
// 省略了子组件注册的过程,import后可直接在template中使用
</script>
- 属性和方法无需返回
(1)vue2.x在template中使用属性和方法栗子-略
(2)vue3.x语法
如需在template中使用属性和方法,必须手动返回对应的属性和方法。这种composition API的编写规则,相对繁琐。如下栗子:
<template>
<div>
<h2 @click="addCount">购买数量 {{ count}} 件</h2>
</div>
</template>
<script>
import { defineComponent, ref } from 'vue';
export default defineComponent({
setup() {
const count = ref(1)
const addCount = () => {
count.value++
}
return {
count,
addCount
}
}
});
</script>
(3)setup script语法
<template>
<div>
<h2 @click="addCount">购买数量 {{ count}} 件</h2>
</div>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(1)
const addCount = () => {
count.value++
}
</script>
- 支持props、emit和context
(1)vue3.x语法
前面setup函数中提及,setup函数包含props和context2个参数,通过这两个参数,达到数据通信及事件触发的目的。(参考官方文档:Setup | Vue.js)
(2)setup scrip语法
没有setup()那怎么获取到props和context呢?
setup script语法糖提供了三个新的API来供我们使用:defineProps、defineEmit和useContext。
defineProps用来接收父组件传来的值props;
defineEmit用来声明触发的事件表;
useContext用来获取组件上下文context
// father
<template>
<div class="radio-card">
<radio-card name="规格" :options="standards" @select="changeOption"/>
</div>
</template>
<script setup>
import { reactive } from 'vue'
import RadioCard from './RadioCard.vue'
const standards = reactive([])
const changeOption = (option) => {
console.log(option)
}
</script>
//child
<template>
<div class="radio-card">
<header class="card-header">
<div class="title"> {{ name }} </div>
</header>
<main class="card-body">
<slot>
<div class="radio-group">
<template v-for="option in options">
<van-button
class="radio-item"
@touchstart="onSelect(option)"
>{{option.value}}</van-button>
</template>
</div>
</slot>
</main>
</div>
</template>
<script setup>
// import { useContext, defineProps, defineEmits } from 'vue'; 待验证-useContext放最后import会报错?
import { defineProps, defineEmits } from 'vue';
const props = defineProps({
name: {
type: String,
default: () => ''
},
options: {
type: Array,
default: () => []
}
});
const emit = defineEmits(['select'])
const onSelect = (option) => {
emit('select', option)
}
</script>
总结:
- setup() 在创建组件之前执行,因此在其中不能使用this。也就不能在setup里用this取对应熟悉数据、方法、computed计算属性里的数据。
- setup可以借助props和context参数,读取属性props,attrs,slots,emit。
- props响应式,慎用解构;context可普通对象解构。eg.const { attrs, slots, emit } = context
二、问题回顾及总结
1. 终端警告提示
如下图:
(1) 编写自定义组件,import了“defineEmits”、“defineProps”、“defineExpose”,终端提示这些api是个编译宏,不再需要导入。
(2) 是因为“defineEmits”、“defineProps”、“defineExpose”是使用setup script语法是定义对应属性、事件等的API,在
2. vue2中sync修饰符的功能,在vue3中如何呈现?
2.1 sync修饰符回顾
vue规则:props 是单向向下绑定的,子组件不能修改props接收过来的外部数据。
- 如果在子组件中修改 props ,Vue会向你发出一个警告。(无法通过修改子组件的props来更改父组件。)而若需要在子组件更新数据时通知父组件同步更新,需要结合$emit和v-on实现。
- 而sync修饰符的作用则是简化事件声明及监听的写法。
如下栗子,比较sync和正常修改数据通知外层的写法:
// 父组件
<template>
<div> 数量: {{num}}</div>
<!-- <ChildComponent :num="num" @increase="num = $event"/> -->
<ChildComponent :num.sync="num" />
</template>
<script>
import ChildComponent from './ChildComponent.vue'
export default {
component: {
ChildComponent
},
data() {
return {
num: 1
}
}
}
</scrip>
//子组件
<template>
<div @click="addNum"> 接收数量: {{num}}</div>
</template>
<script>
export default {
props: ['num'],
// data() {
// return {
// childNum: this.num
// }
// },
methods: {
addNum() {
// this. childNum++
// this.$emit('increase', this. childNum)
this.$emit('update:num', this.num + 1)
}
}
}
</scrip>
2.2 sync的语法糖功能在vue3中如何编写使用?
vue3中,通过 v-model:propName 实现自定义组件的间数据的双向绑定。看栗子:
// 子组件 ActionSheet.vue
<template>
<div class="ds-action-sheet">
<!-- v-model:show 是vant组件抛出的v-model的属性 -->
<van-action-sheet
v-model:show="visible"
:title="title"
:closeable="closeable"
:close-on-click-overlay="closeOnClickOverlay"
:actions="actions"
@select="onSelect"
@close="onClose"
@click-overlay="onClickOverlay"
@cancel="onCancel"
>
<slot></slot>
</van-action-sheet>
</div>
</template>
<script setup>
const props = defineProps({
visible: {
type: Boolean,
default: () => false
},
// 是否在点击遮罩层后关闭
closeOnClickOverlay: {
type: Boolean,
default: () => true
},
title: {
type: String,
default: () => ''
},
// 面板选项列表
actions: {
type: Array,
default: () => []
}
})
const emit = defineEmits(['update:visible', 'select', 'close', 'click-overlay'])
const onSelect = () => {
emit('select')
}
const onClose = () => {
// 关键句,父组件则可通过 v-model:visible 同步子组件更新后的数据
emit('update:visible')
emit('close')
}
const onCancel = () => {
// cancel事件,修复打包后在微信浏览器无法更新visible值问题
emit('update:visible')
emit('cancel')
}
const onClickOverlay = () => {
emit('click-overlay')
if(props.closeOnClickOverlay) {
// click-overlay事件 修复打包后在微信浏览器无法更新visible值问题
emit('update:visible')
}
}
</script>
// 父组件
<template>
<van-button @click="showActionSheet">弹出弹层</van-button>
<ds-action-sheet
title="do a test"
v-model:visible="mVisilbe"
>
<div>弹层内容</div>
</ds-action-sheet>
</template>
<script setup>
import { ref } from 'vue';
import DsActionSheet from './ActionSheet.vue';
const mVisilbe = ref(false)
const showActionSheet = () => {
mVisilbe.value = true
}
</script>
总结:
- 父组件通过 “v-model:绑定的属性名”传递数据属性,支持绑定多个属性;
- 子组件配置emits,通过 “update:属性名” 的格式定义更新事件
3. vant+vue3,二次封装的ActionSheet组件(见2.2的栗子)问题
问题:打包后在微信浏览器中点击弹层的关闭按钮或点击遮罩层(已配置点击遮罩层关闭弹层配置项),无法正常关闭弹层。(本地运行可正常关闭)
解决:在对应事件中,添加 emit(‘update:visible’) ,手动添加更新visible值。见上栗子中的47行、52行及onClickOverlay 函数中的条件判断处理
4. vue3不支持过滤器功能
在 3.x 中,处理通用文本格式的过滤器功能已删除,不再支持。建议用方法调用或计算属性替换它们。
<template>
<div>
<span>总价:</span>
<span class="unit">¥</span>
<span class="price">
{{ amountSeparatorFormatter(totalPrice) }}
</span>
</div>
</template>
<script setup>
const amountSeparatorFormatter = (value, fixedNum = 2) => {
if (!value) {
return;
}
if (isNaN(value)) {
return value;
}
let val = Number(value).toFixed(fixedNum).toString();
val = val.replace(/\./, ',')
while (/\d{4}/.test(val)) {
val = val.replace(/(\d+)(\d{3}\,)/, '$1,$2')
}
return val.replace(/\,(\d*)$/, '.$1')
}
</script>
若应用中存在全局过滤器,可以定义全局属性在所有组件应用次全局属性。eg:
<template>
<h1>使用全局属性</h1>
<p>{{ $filters. currencyShow(money) }}</p>
</template>
// main.js
const app = createApp(App)
app.config.globalProperties.$filters = {
currencyShow(value) {
return '¥' + value
}
}
参考文档: https://vue3.chengpeiquan.com/
转载请标明出处!
更多推荐
所有评论(0)