官方建议我们使用大驼峰命名法注册组件,因为:
使Vue组件比原生HTML元素更醒目。例如,使用组件Pascalcase.vue
使用驼峰命名组件!
使用更细节的方式定义属性:
自定义事件的名称会被自动做转换,我们通常使用驼峰做事件名,但监听时需要转换为肉串方式。
例如:
script setup中定义
在vue3中,那些没有明确在组件props和emits中声明的特性或事件监听器称为透传特性,以前叫非属性特性。比如class
,style
和id
特性。当组件只有单根时,透传特性自动被添加到根元素上作为其特性。例如:
如果不想自动继承特性,可以使用inheritAttrs: false
禁止
Vue3中插槽的变化是移除scopeSlots
,只需要访问slots
对象,且包括default
插槽都是函数形式。
访问透传特性
如果要传递模板内容给子组件,我们使用插槽。
隔代传参时,使用provide/inject这组API。
import { inject } from 'vue'
export default {
setup() {
// 后代注入数据
inject(/* key */ 'message', /* value */ 'hello!')
}
}
利用Composition API封装的可重用状态逻辑称为composables
。
约定composables函数命名时加上use前缀,例如:
// mouse.js
import { ref, onMounted, onUnmounted } from 'vue'
// by convention, composable function names start with "use"
export function useMouse() {
// state encapsulated and managed by the composable
const x = ref(0)
const y = ref(0)
// a composable can update its managed state over time.
function update(event) {
x.value = event.pageX
y.value = event.pageY
}
// a composable can also hook into its owner component's
// lifecycle to setup and teardown side effects.
onMounted(() => window.addEventListener('mousemove', update))
onUnmounted(() => window.removeEventListener('mousemove', update))
// expose managed state as return value
return { x, y }
}
传入refs参数代替原始值
import { unref } from 'vue'
function useFeature(maybeRef) {
// if maybeRef is indeed a ref, its .value will be returned
// otherwise, maybeRef is returned as-is
const value = unref(maybeRef)
}
总是返回包含refs的对象
// x and y are refs
const { x, y } = useMouse()
组件通信常⽤⽅式,vue3中有很多变化:
{
props: { msg: String }
}
除了props选项,vue3.2还出了script setup的新写法
const props = defineProps({
model: { type: Object, required: true }
});
props.model
现在只剩下派发事件的emit方法
this.$emit('add', good)
vue3.2还出了script setup的新写法
const emit = defineEmits(['update:model-value', 'validate'])
const emit = defineEmits<{
(e: "update:model-value", value: string): void;
(e: "validate"): void;
}>();
emit("update:model-value", inp.value);
o n , on, on,once, $off被移除了!
上述3个⽅法被认为不应该由vue提供,因此被移除了,可以使⽤其他库实现等效功能。
import mitt from 'mitt'
const emitter = mitt()
// 发送事件
emitter.emit('foo', 'foooooooo')
// 监听事件
emitter.on('foo', msg => console.log(msg))
vue2
时代我们常常使用一个vue实例来做事件总线,现在不行了:
所以我们就使用上面的mitt
方案来代替就好了!
// vue2时代,现在因为没有$on不行了
Vue.prototype.$bus = new Vue()
// 组件里面
this.$bus.$emit('xxx')
// 其他组件
this.$bus.$on('xxx', () => {})
pinia
vuex 4.x中的composition api写法:
const store = useStore()
store.commit('add')
store.dispatch('add')
兄弟组件之间通信可通过共同祖辈搭桥。
// brother1
this.$parent.$on('foo', handle)
// brother2
this.$parent.$emit('foo')
vue3中移除了该选项,官方建议我们访问子组件时使用$refs
获取指定元素或组件
// parent
mounted() {
this.$refs.hw.xx = 'xxx'
}
能够实现祖先和后代之间传值
在composition中有对应的api
// ancestor
provide() {
return {foo: 'foo'}
}
// descendant
inject: ['foo']
import {provide, inject} from vue
// 提供数据
provide(key, value)
// 注入数据
inject(key)
a t t r s 会包含那些没有声明的组件特性, v u e 3 中移除了 attrs会包含那些没有声明的组件特性,vue3中移除了 attrs会包含那些没有声明的组件特性,vue3中移除了listeners,只剩下$attrs:
// child:并未在props中声明foo
{{$attrs.foo}}
// parent
通过 v-bind=“$attrs” 透传到内部组件——在创建⾼级别的组件时⾮常有⽤:
// 给Grandson隔代传值,parent.vue
// Child做展开
// Grandson使⽤
{{msg}}
插槽语法是Vue 实现的内容分发 API,⽤于复合组件开发。该技术在通⽤组件库开发中有⼤量应⽤。
slot称为匿名插槽,作为占位符存在,将来被替换为传入内容。
// comp1
// parent
hello
slot加上name就称为具名插槽,可以将内容分发到⼦组件指定位置
// comp2
// parent
具名插槽
内容...
分发内容要⽤到⼦组件中的数据
// comp3
// parent
来⾃⼦组件数据:{{slotProps.foo}}
全局静态⽅法引发⼀些问题,vue3将global-api改为app实例⽅法
// vue2中
// Vue.component()
// vue3中
const app = createApp({})
.component('comp', {template: 'i am comp'})
.mount('#app')
以前.sync和v-model功能有重叠,容易混淆,vue3做了统⼀。
app.component('comp', {
props: {
modelValue
},
template: `
i am comp, {{modelValue}}
`,
props: ['modelValue'],
})
不再传⼊h函数,需要我们⼿动导⼊;拍平的props结构。scopedSlots删掉了,统⼀到slots
import {h} from 'vue'
export default {
render() {
const emit = this.$emit
const onclick = this.onclick
return h('div', [
h('div', { onClick(){ emit('update:modelValue', 'new value')} },
`i am comp, ${this.modelValue}`),
h('button', { onClick(){ onclick() }}, 'buy it!')
])
},
}
该选项⽤于标注⾃定义事件及其校验等。
createApp({}).component("comp", {
template: `...`,
// emits标明组件对外事件
emits: ['buy', '...']
// 还能对事件进行校验
emits: {
'update:modelValue': null, // 不做校验
buy(p) { // 校验buy事件
if (p === 'nothing') {
console.warn('参数⾮法');
return false
} else {
return true
}
}
},
})