25 个 Vue 技巧,开发了 5 年了,才知道还能这么用

作者 | 前端小智
1. 将一个 prop 限制在一个类型的列表中
export default { name: 'Image', props: { src: { type: String, }, style: { type: String, validator: s => ['square', 'rounded'].includes(s) } }};
2. 默认内容和扩展点
<button class="button" @click="$emit('click')"> <slot> <!-- Used if no slot is provided --> Click me </slot></button>
<template> <button class="button" @click="$emit('click')"> <slot> <div class="formatting"> {{ text }} </div> </slot> </button></template>
<!-- Uses default functionality of the component --><ButtonWithExtensionPoint text="Formatted text" /><ButtonWithExtensionPoint><div class="different-formatting">Do something a little different here</div></ButtonWithExtensionPoint>
3. 使用引号来监听嵌套属性
watch { '$route.query.id'() { // ... }}
4. 知道何时使用v-if(以及何时避免使用)
<ComplicatedChart v-show="chartEnabled" />
5. 单个作用域插槽的简写(不需要 template 标签)
<DataTable> <template #header="tableAttributes"> <TableHeader v-bind="tableAttributes" /> </template></DataTable>
<DataTable #header="tableAttributes"> <TableHeader v-bind="tableAttributes" /></DataTable>
6. 有条件地渲染插槽
const $slots = { default: <default slot>, icon: <icon slot>, button: <button slot>,};
<!-- Slots.vue --><template> <div> <h2>Here are some slots</h2> <slot /> <slot name="second" /> <slot name="third" /> </div></template>
<template><Slots><template #second>This will be applied to the second slot.</template></Slots></template>$slots = { second: <vnode> }
<template> <div> <h2>A wrapped slot</h2> <div v-if="$slots.default" class="styles"> <slot /> </div> </div></template>
那么,为什么我们希望能够有条件地渲染插槽呢?
当使用封装的div来添加默认样式时 插槽是空的 如果我们将默认内容与嵌套槽相结合
<template> <div> <h2>This is a pretty great component, amirite?</h2> <div class="default-styling"> <slot > </div> <button @click="$emit('click')">Click me!</button> </div></template>
<div> <h2>This is a pretty great component, amirite?</h2> <div class="default-styling"> <!-- 槽中没有内容,但这个div 仍然被渲染。糟糕 --> </div> <button @click="$emit('click')">Click me!</button></div>
7. 如何监听一个插槽的变化
<!-- 可惜这个事件不存在 --><slot @change="update" />
MutationObserver接口提供了监视对DOM树所做更改的能力。它被设计为旧的Mutation Events功能的替代品,该功能是DOM3 Events规范的一部分。
export default {mounted() {// 当有变化时调用`update`const observer = new MutationObserver(this.update);// 监听此组件的变化observer.observe(this.$el, {childList: true,subtree: true});}};
8. 将局部和全局的style混合在一起
<style scoped> .component { background: green; }</style>
<style>/* 全局 */.component p {margin-bottom: 16px;}</style><style scoped>/* 在该组件内有效 */.component {background: green;}</style>
9. 重写子组件的样式--正确的方法
<style scoped>.my-component >>> .child-component { font-size: 24px;}</style>
10. 用上下文感知组件创造魔法
1.状态共享
<!-- 为简单起见,作为一个单一组件使用 --><Dropdown v-model="selected" :options="[]" /><!-- 分多个组件,更灵活 --><Select v-model="selected"><Option value="mustard">Mustard</Option><Option value="ketchup">Ketchup</Option><div class="relish-wrapper"><Option value="relish">Relish</Option></div></Select>
2. Configuration
3.样式
.statistic {color: black;font-size: 24px;font-weight: bold;}.statistic + .statistic {margin-left: 10px;}
11. 如何在Vue之外创建一个具有响应性的变量(Vue2和3)
const externalVariable = getValue();export default {data() {return {reactiveVariable: externalVariable,};}};
import { ref } from 'vue';// 可以完全在Vue组件之外完成const externalVariable = getValue();const reactiveVariable = ref(externalVariable);console.log(reactiveVariable.value);
import { reactive } from 'vue';// 可以完全在Vue组件之外完成const externalVariable = getValue();// reactive 只对对象和数组起作用const anotherReactiveVariable = reactive(externalVariable);// Access directlyconsole.log(anotherReactiveVariable);
12. v-for 中的解构
<li v-for="{ name, id } in users" :key="id"> {{ name }}</li>
<li v-for="(movie, index) in [ 'Lion King', 'Frozen', 'The Princess Bride']"> {{ index + 1 }} - {{ movie }}</li>
<li v-for="(value, key) in { name: 'Lion King', released: 2019, director: 'Jon Favreau',}"> {{ key }}: {{ value }}</li>
<li v-for="(value, key, index) in { name: 'Lion King', released: 2019, director: 'Jon Favreau',}"> #{{ index + 1 }}. {{ key }}: {{ value }}</li>
13. 在指定范围内循环
<template> <ul> <li v-for="n in 5">Item #{{ n }}</li> </ul></template>
Item #1Item #2Item #3Item #4Item #5
14. 监听你的组件中的任何东西
export default { computed: { someComputedProperty() { // Update the computed prop }, }, watch: { someComputedProperty() { // Do something when the computed prop is updated } }};
计算属性 props 嵌套值
15.窃取 prop 类型
<template> <div> <h2>{{ heading }}</h2> <Icon :type="iconType" :size="iconSize" :colour="iconColour" /> </div></template>
import Icon from './Icon';export default { components: { Icon }, props: { iconType: { type: String, required: true, }, iconSize: { type: String, default: 'medium', validator: size => [ 'small', 'medium', 'large', 'x-large' ].includes(size), }, iconColour: { type: String, default: 'black', }, heading: { type: String, required: true, }, },};
import Icon from './Icon';export default { components: { Icon }, props: { ...Icon.props, heading: { type: String, required: true, }, },};
import Icon from './Icon';const iconProps = {};Object.entries(Icon.props).forEach((key, val) => {iconProps[`icon${key.toUpperCase()}`] = val;});export default {components: { Icon },props: {...iconProps,heading: {type: String,required: true,},},};
16. 检测元素外部(或内部)的单击
window.addEventListener('mousedown', e => { // 获取被点击的元素 const clickedEl = e.target; if (el.contains(clickedEl)) { //在 "el "里面点击了 } else { //在 "el "外点击了 }});
17. 递归插槽
<!-- VFor.vue --><template> <div> <!-- 渲染第一项 --> {{ list[0] }} <!-- 如果我们有更多的项目,继续!但是不要使用我们刚刚渲染的项 --> <v-for v-if="list.length > 1" :list="list.slice(1)" /> </div></template>
<template><div><!-- Pass the item into the slot to be rendered --><slot v-bind:item="list[0]"><!-- Default -->{{ list[0] }}</slot><v-forv-if="list.length > 1":list="list.slice(1)"><!-- Recursively pass down scoped slot --><template v-slot="{ item }"><slot v-bind:item="item" /></template></v-for></div></template>
<template><div><!-- 常规列表 --><v-for :list="list" /><!-- 加粗的项目列表 --><v-for :list="list"><template v-slot="{ item }"><strong>{{ item }}</strong></template></v-for></div></template>
18. 组件元数据

export default {name: 'LiveUsersWidget',// 👇 只需将其作为一个额外的属性添加columns: 3,props: {// ...},data() {return {//...};},};export default {name: 'LiveUsersWidget',// 👇 只需将其作为一个额外的属性添加columns: 3,props: {// ...},data() {return {//...};},};
import LiveUsersWidget from './LiveUsersWidget.vue';const { columns } = LiveUsersWidget;
export default { name: 'LiveUsersWidget', columns: 3, created() { // 👇 `$options` contains all the metadata for a component console.log(`Using ${this.$options.metadata} columns`); },};
保持单个组件的版本号 用于构建工具的自定义标志,以区别对待组件 在计算属性、数据、watch 等之外为组件添加自定义功能 其它
19. 多文件单文件组件
<template src="./template.html"></template><script src="./script.js"></script><style scoped src="./styles.css"></style>
20. 可重复使用的组件并不是你所想的那样
<!-- OverflowMenu.vue --><template> <Menu> <!-- 添加一个自定义按钮来触发我们的菜单 --> <template #button v-slot="bind"> <!-- 使用bind来传递click处理程序、a11y 属性等 --> <Button v-bind="bind"> <template #icon> <svg src="./ellipsis.svg" /> </template> </Button> </template> </Menu></template>
21. 从组件外部调用一个方法
<!-- Parent.vue --><template><ChildComponent ref="child" /></template>// Somewhere in Parent.vuethis.$refs.child.method();
<template><ChildComponent:tell-me-what-to-do="someInstructions"@something-happened="hereIWillHelpYouWithThat"/></template>// Child.vueexport default {props: ['trigger'],watch: {shouldCallMethod(newVal) {if (newVal) {// Call the method when the trigger is set to `true`this.method();}}}}
父组件将 true 传递给触发器 prop Watch 被触发,然后 Child 组件调用该方法 子组件发出一个事件,告诉父组件该方法已被成功触发 Parent组件将 trigger 重置为 false,所以我们可以从头再来一次
<!-- Parent.vue --><template><ChildComponent ref="child" /></template>// Somewhere in Parent.vuethis.$refs.child.method();
22. 监听数组和对象
export default {name: 'ColourChange',props: {colours: {type: Array,required: true,},},watch: {// 使用对象语法,而不仅仅是方法colours: {// 这将让Vue知道要在数组内部寻找deep: true,handler()console.log('The list of colours has changed!');}}}}
watch( colours, () => { console.log('The list of colours has changed!'); }, { deep: true, });
23. 用Vue Router进行深度链接
someurl.com/edit?date-range=last-week
const dateRange = this.$route.query.dateRange;
<RouterLink :to="{ query: { dateRange: newDateRange }}">
24. template 标签的另一个用途
<template> <div class="card"> <img src="imgPath" /> <h3> {{ title }} </h3> <h4 v-if="expanded"> {{ subheading }} </h4> <div v-if="expanded" class="card-content" > <slot /> </div> <SocialShare v-if="expanded" /> </div></template>
<template> <div class="card"> <img src="imgPath" /> <h3> {{ title }} </h3> <template v-if="expanded"> <h4> {{ subheading }} </h4> <div class="card-content"> <slot /> </div> <SocialShare /> </template> </div></template>
25. 处理错误(和警告)的更好方法
// Vue 3const app = createApp(App);app.config.errorHandler = (err) => {alert(err);};// Vue 2Vue.config.errorHandler = (err) => {alert(err);};
赞 (0)
