使用@vue/cli
创建模版项目(啥是@vue/cli)
具体操作自行百度
提示:
@vue/cli
脚手架默认生成的项目是零webpack
配置,但是可以支持自定义webpack
配置。只需在根目录下新建vue.config.js
配置文件,这个文件会被@vue/cli-service
自动加载。
vue.config.js
基础配置模版:
const path = require("path");
const sourceMap = process.env.NODE_ENV === "development";
module.exports = {
// 基本路径
publicPath: "./",
// 输出文件目录
outputDir: "dist",
// eslint-loader(作用:对编译前的ES6语法进行检查) 是否在保存的时候检查
lintOnSave: false,
// webpack配置
chainWebpack: () => {},
configureWebpack: config => {
if (process.env.NODE_ENV === "production") {
// 为生产环境修改配置
config.mode = "production";
} else {
// 为开发环境修改配置
config.mode = "development";
}
Object.assign(config, {
// 开发生产共同配置
resolve: {
extensions: [".js", ".vue", ".json", ".ts", ".tsx"],
alias: {
vue$: "vue/dist/vue.js",
"@": path.resolve(__dirname, "./src"),
"@c": path.resolve(__dirname, "./src/components")
}
}
});
},
// 生产环境是否生成 sourceMap 文件
productionSourceMap: sourceMap,
// css相关配置
css: {
// 是否使用css分离插件 ExtractTextPlugin
extract: true,
// 开启 CSS source maps?
sourceMap: false,
// css预设器配置项
loaderOptions: {},
// 设置为 false 后你就可以去掉文件名中的 .module 并将所有的 *.(css|scss|sass|less|styl(us)?)
requireModuleExtension: false
},
// use thread-loader for babel & TS in production build
// enabled by default if the machine has more than 1 cores
parallel: require("os").cpus().length > 1,
// PWA 插件相关配置
// see https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa
pwa: {},
// webpack-dev-server 相关配置
devServer: {
open: true,// 启动后自动打开浏览器
host: "localhost",
port: 8080,
https: false,
hotOnly: false,
proxy: {
// 设置代理
// proxy all requests starting with /api to jsonplaceholder
"/api": {
target: "http://localhost:3000/",
changeOrigin: true,
ws: true,
pathRewrite: {
"^/api": ""
}
}
},
before: app => {}
},
// 第三方插件配置
pluginOptions: {
// ...
}
};
注意
TypeScript
开发环境默认只能识别.ts
,.tsx
。因此,在导入vue
文件的时候,需要加上后缀名.vue
src
目录下:
shims-tsx.d.ts
.tsx
的文件,在vue项目中写jsx代码shims-vue.d.ts
.vue
为后缀的文件交给vue模块来处理declare module '*.vue' {
import Vue from 'vue'
export default Vue
}
使用 Vue.component
或 Vue.extend
定义组件;
Vue.extend
使用基础的Vue构造器,创建一个“子类”,这种方式最接近Vue
的单文件组件写法。
import Vue from 'vue'
const Component = Vue.extend({
// 类型推断已启用
})
const Component = {
// 这里不会有类型推断,
// 因为 TypeScript 不能确认这是 Vue 组件的选项
}
vue-class-component
和 vue-property-decorator
yarn add vue-class-component vue-property-decorator --save-dev
vue-class-component
官方出品(官方文档)
是 vue 的官方库,作用是用类的方式编写组件,提供了Vue、Component等;
vue-property-decorator
社区出品(文档)
深度依赖了vue-class-component
,拓展出了更多操作符:@Prop
、@Emit
、@Inject
、@Model
、@Provide
、@Watch
vue-property-decorator
可以说是vue-class-component
的一个超集,正常开发时只需使用vue-property-decorator
即可。
具备以下几个装饰器和功能:
@Prop
@PropSync
@Model
@Watch
@Provide
@Inject
@ProvideReactive
@InjectReactive
@Emit
@Ref
@Component
(由 vue-class-component提供)Mixins
(由 vue-class-component提供)官方文档:https://www.npmjs.com/package/vue-property-decorator
@Prop(options: (PropOptions | Constructor[] | Constructor) = {})
@Prop
装饰器接收一个参数,这个参数可以有三种写法:
示例代码:
import { Vue, Component, Prop } from 'vue-property-decorator'
@Component
export default class YourComponent extends Vue {
@Prop(Number) readonly propA: number | undefined
@Prop({ default: 'default value' }) readonly propB!: string
@Prop([String, Boolean]) readonly propC: string | boolean | undefined
}
等同于:
export default {
props: {
propA: {
type: Number,
},
propB: {
default: 'default value',
},
propC: {
type: [String, Boolean],
},
},
}
@PropSync(propName: string, options: (PropOptions | Constructor[] | Constructor) = {})
@PropSync装饰器与@prop用法类似,二者的区别在于:
示例代码:
import { Vue, Component, PropSync } from 'vue-property-decorator'
@Component
export default class YourComponent extends Vue {
@PropSync('name', { type: String }) syncedName!: string
}
等同于:
export default {
props: {
name: {
type: String,
},
},
computed: {
syncedName: {
get() {
return this.name
},
set(value) {
this.$emit('update:name', value)
},
},
},
}
@Model(event?: string, options: (PropOptions | Constructor[] | Constructor) = {})
@Model装饰器允许我们在一个组件上自定义v-model,接收两个参数:
示例代码:
import { Vue, Component, Model } from 'vue-property-decorator'
@Component
export default class YourComponent extends Vue {
@Model('change', { type: Boolean }) readonly checked!: boolean
}
相当于:
export default {
model: {
prop: 'checked',
event: 'change',
},
props: {
checked: {
type: Boolean,
},
},
}
<template>
<input
type="text"
:value="value"
@change="$emit('change', $event.target.value)"
/>
</template>
@Watch(path: string, options: WatchOptions = {})
@Watch 装饰器接收两个参数:
示例代码:
import { Vue, Component, Watch } from 'vue-property-decorator'
@Component
export default class YourComponent extends Vue {
@Watch('child')
onChildChanged(val: string, oldVal: string) {}
@Watch('person', { immediate: true, deep: true })
onPersonChanged1(val: Person, oldVal: Person) {}
@Watch('person')
onPersonChanged2(val: Person, oldVal: Person) {}
}
等同于:
export default {
watch: {
child: [
{
handler: 'onChildChanged',
immediate: false,
deep: false,
},
],
person: [
{
handler: 'onPersonChanged1',
immediate: true,
deep: true,
},
{
handler: 'onPersonChanged2',
immediate: false,
deep: false,
},
],
},
methods: {
onChildChanged(val, oldVal) {},
onPersonChanged1(val, oldVal) {},
onPersonChanged2(val, oldVal) {},
},
}
注意: 监听发生在beforeCreate
勾子之后,created
勾子之前
@Provide(key?: string | symbol)
@Inject(options?: { from?: InjectKey, default?: any } | InjectKey)
@Provide(key?: string | symbol)
@InjectReactive(options?: { from?: InjectKey, default?: any } | InjectKey)
@Emit(event?: string)
@Ref(refKey?: string)
@Ref 装饰器接收一个可选参数,用来指向元素或子组件的引用信息。如果没有提供这个参数,会使用装饰器后面的属性名充当参数
@Component(options:ComponentOptions = {})
@Component 装饰器可以接收一个对象作为参数,可以在对象中声明 components ,filters,directives等未提供装饰器的选项,也可以声明computed,watch等
Vue.extend()
props
,components
和data
与原JavaScript没任何区别。computed
,methods
,watch
也没啥大改变,但是有this
参与运算的必须标明返回值类型,不然会报错;mixins
多混入的效果,只能混入一个(不推荐使用混入,无法实现多继承,Issue)vue-class-component
/vue-property-decorator
props
,components
和watch
等需使用装饰器;data
直接在类里面写变量;computed
写法类似getter
和setter
;methods
就直接在里面写方法;