Vue2里的export default到底是什么?怎么用才对?
在Vue2项目里写组件时,“export default”几乎是天天见的代码,但不少刚入门的同学还是搞不清它到底是干啥的、怎么用才对,甚至和其他导出方式混淆,今天就把Vue2里export default的关键知识点拆成问题逐个讲透,不管是组件结构、和其他导出方式的区别,还是避坑技巧,看完心里就有数啦~
Vue2里的export default,本质是在搞啥事儿?
Vue2项目能用上export default,核心是ES6的模块导出语法在起作用,咱们写的每个.vue
单文件组件,本质上都是一个独立的JS模块(哪怕里面有template
、style
,最终也会被工具链转成JS),而export default
默认导出”这个模块里的核心内容——对于Vue组件来说,就是导出包含组件选项(像data
、methods
、props
这些)的对象。
举个最直观的例子,一个简单的Vue组件长这样:
<template> <div>{{ msg }}</div> </template> <script> export default { name: 'HelloWorld', data() { return { msg: '你好,Vue2!' } } } </script>
这里的export default
后面跟着的对象,就是把这个组件的“配置信息”对外暴露出去,其他文件想复用这个组件时,用import 自定义名称 from './HelloWorld.vue'
就能拿到这个对象,Vue会自动把它处理成可渲染的组件实例。
另外得注意,每个JS模块只能有一个export default
,这和“命名导出(export
)”不一样(命名导出可以有多个,后面会对比),正因为是“默认”,所以import
的时候不用像命名导出那样写大括号,还能自己给导入的内容起名字,灵活性很高。
写Vue2组件时,export default里该塞哪些东西?
在Vue2的组件里,export default
后面跟的是组件选项对象,里面能配置的内容特别多,核心的有这些:
name
:给组件起个名字,调试的时候(比如Vue DevTools里看组件层级)特别方便,还能实现组件递归(自己调用自己),比如name: 'MyComponent'
,递归场景下组件内部用<MyComponent />
就能调用自己。data
:必须是函数!返回一个对象,里面存组件的私有数据,要是写成对象(比如data: { msg: 'xxx' }
),多个组件实例会共享同一份数据,一改全改,踩过这个坑的同学肯定懂有多坑…props
:定义组件接收父组件传的值,像props: ['parentMsg']
或者更严谨的对象形式props: { parentMsg: { type: String, required: true } }
,负责组件间的数据传递。methods
:放组件的方法,比如事件处理函数、业务逻辑函数,像methods: { handleClick() { ... } }
,方法里的this
默认指向组件实例。computed
:计算属性,基于已有数据生成新数据,有缓存特性,比如computed: { fullName() { return this.firstName + this.lastName } }
,依赖不变就不会重复计算。watch
:侦听数据变化做操作,比如watch: { msg(newVal, oldVal) { ... } }
,能深度侦听对象/数组变化(开deep: true
)。- 生命周期钩子:像
created
(实例创建完,数据观测、事件配置好了,但没挂载DOM)、mounted
(DOM挂载完成,能操作DOM了)这些,在特定阶段执行逻辑。
举个更完整的例子,一个带交互的组件:
<template> <div> <p>{{ count }}</p> <button @click="increment">+1</button> </div> </template> <script> export default { name: 'Counter', data() { return { count: 0 } }, methods: { increment() { this.count++ } }, created() { console.log('组件创建好啦,count初始值是', this.count) } } </script>
这里export default
里的name
、data
、methods
、created
各司其职,共同撑起组件的功能和逻辑~
export default和export有啥区别?在Vue项目里咋选?
很多同学会把export default
和export
搞混,其实它们是ES6模块里两种不同的导出方式,区别大着呢:
规则层面:
export default
:每个模块只能有一个默认导出,导入时用import 任意名称 from '模块路径'
,名字自己定,不用管导出时的名字。export
(命名导出):一个模块可以有多个命名导出,导入时必须用import { 导出时的名字 } from '模块路径'
,名字得和导出时对应,除非用as
重命名。
Vue项目里的实际用法:
在Vue2开发中,组件文件(.vue)几乎都用export default
,因为一个.vue
文件对应一个组件,用默认导出最直观,导入时还能随便起名字,
// 导出(HelloWorld.vue里) export default { name: 'HelloWorld', ... } // 导入(其他组件里) import MyHello from './HelloWorld.vue' // 名字改成MyHello也能用
而export
(命名导出)更适合工具库、工具函数文件,比如写了个utils.js
,里面有多个工具函数:
// utils.js export function formatTime(time) { ... } export function deepClone(obj) { ... } // 其他文件导入 import { formatTime, deepClone } from './utils.js' // 或者重命名 import { formatTime as ft } from './utils.js'
简单说,Vue组件是“单模块单导出”,用export default
;多函数/多常量的工具文件是“单模块多导出”,用export
更灵活~
用export default时,哪些坑容易踩?咋避?
写多了组件,总会在export default
这儿栽跟头,这些高频坑得提前避:
坑1:data
写成对象,不是函数
错误写法:
export default { data: { // 错!单文件组件里data必须是函数 msg: '错啦' } }
后果:多个组件实例会共享同一份data
,比如列表里每个项用了这个组件,点一个全变。
解决:改成函数返回对象:
data() { return { msg: '对啦' } }
坑2:组件选项语法错误,比如少写逗号、钩子名拼错
错误示例:
export default { name: 'MyComp' data() { // 这里少了逗号,会报语法错 return { ... } }, mounted() { ... }, mouted() { ... } // 钩子名mouted拼错,不会执行! }
后果:要么代码直接报错跑不起来,要么生命周期钩子没触发,逻辑丢了。
解决:写的时候多检查语法,IDE装个Vue插件(比如Volar),能实时提示语法错误;生命周期钩子名记准(像mounted
、updated
这些)。
坑3:import
时路径写错,找不到模块
错误示例:
import MyComp from '../components/MyComp.vue' // 实际文件是MyComponent.vue,路径或文件名错了
后果:浏览器控制台报“Module not found”,组件渲染不出来。
解决:养成好习惯,路径用相对路径时,检查或对不对;文件名大小写也要和实际文件一致(有些系统区分大小写)。
坑4:和Vuex、Vue Router结合时导出不对
比如Vuex模块用命名导出,结果Vuex识别不了:
错误写法(Vuex模块文件):
export const myModule = { // 用命名导出,Vuex默认找export default state: { ... }, mutations: { ... } }
后果:Vuex注册模块时读不到这个模块,状态管理失效。
解决:Vuex模块要用export default
导出:
export default { state: { ... }, mutations: { ... } }
同理,Vue Router的路由组件配置里,组件导入要确保是默认导出的组件~
大型Vue2项目里,export default咋管理更高效?
当项目变大,组件越来越多,export default
的写法也得讲究“高效复用、逻辑分层”,分享几个实用思路:
思路1:组件拆分+单一职责,每个组件export default
清晰
把大组件拆成小组件,每个.vue
文件只负责一块逻辑,export default
里的选项也更简洁,比如一个复杂的表单组件,拆成FormItem.vue
、FormButton.vue
等子组件,每个子组件的export default
只关注自己的props
、methods
,维护起来更轻松。
思路2:用mixins抽离重复逻辑
多个组件有相同逻辑(比如都要处理表单验证、都要监听窗口resize),可以把这些逻辑写到mixins里,mixins本身也是export default
一个对象:
// mixins/resizeMixin.js export default { data() { return { windowWidth: 0 } }, mounted() { window.addEventListener('resize', this.handleResize) }, beforeDestroy() { window.removeEventListener('resize', this.handleResize) }, methods: { handleResize() { this.windowWidth = window.innerWidth } } } // 在组件里用mixins import resizeMixin from './mixins/resizeMixin.js' export default { mixins: [resizeMixin], // 自动合并mixins里的选项 name: 'MyComponent', ... }
这样多个组件能复用resize相关逻辑,不用重复写生命周期和方法~
思路3:结合TypeScript增强类型(Vue2+TS场景)
Vue2对TS的支持需要借助defineComponent
,写法变成:
<script lang="ts"> import { defineComponent } from 'vue' export default defineComponent({ name: 'MyComp', data() { return { count: 0 // TS能推断count是number类型 } }, props: { msg: { type: String, required: true } } }) </script>
defineComponent
能让TS更智能地推断组件选项的类型,避免props
传错类型、方法里this
指向错误等问题,大型项目里类型约束能减少很多 bug~
Vue2里有没有不用export default的替代写法?
其实在Vue2里,export default
不是唯一的导出方式,还有两种“替代方案”,但各有适用场景:
方案1:用CommonJS的module.exports
(webpack支持)
早期Vue项目没用babel处理ES6模块时,会用CommonJS语法:
<template>...</template> <script> const MyComponent = { name: 'MyComp', data() { ... } } module.exports = MyComponent </script>
导入时用const MyComp = require('./MyComponent.vue')
,但现在Vue项目基本都用babel+webpack,支持ES6模块,export default
更简洁,所以这种写法逐渐淘汰了。
方案2:用Vue.extend
创建组件构造器再导出
Vue.extend是Vue2里创建组件构造器的API,写法:
<template>...</template> <script> import Vue from 'vue' const MyComponent = Vue.extend({ name: 'MyComp', data() { ... } }) export default MyComponent </script>
这种写法和直接export default { ... }
的区别是:前者是“组件构造器”,后者是“组件选项对象”,但Vue Loader处理单文件组件时,会自动把export default { ... }
的选项传给Vue.extend
,所以两种写法最终效果一样。实际开发中更推荐直接写export default
对象,代码更少更直观。
看完这些问题,是不是对Vue2里的`export default`从“眼熟但模糊”变成“清晰会用”了?简单总结下:它是ES6默认导出语法在Vue组件里的实践,负责把组件的配置对外暴露,和命名导出分工不同;写的时候要注意`data`必须是函数、选项语法正确这些细节;大型项目里结合拆分、mixins、TS能玩出更多效率花样~下次写组件时,再遇到`export default`就不会犯懵,还能避坑高效写代码啦~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。