欢迎使用「积木小盒」
01
快速使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>01</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="root">
<p>{{ message }}</p>
</div>
<script>
// 创建vue实例
const app = new Vue({
// 根DOM元素的CSS选择器
el: '#root',
// 一些数据
data () {
return {
message: 'vue',
}
}
})
</script>
</body>
</html>
开发者工具
推荐使用Chrome的Vue.js devtools调试工具,极大提高调试效率
借助模板实现DOM的动态性
模板是描述View最简单的方法,只需少量额外语法就能实现DOM的动态更新
文本插值
<div id="root">
<p>{{ message }}</p>
</div>
此时数据和视图已经绑定了。vue框架有一个非常强大且高效的响应式系统,打开控制台输入app.message='test',视图也会自动更新显示test。
利用指令添加基本的交互
使用v-model实现数据和视图的双向绑定
<div id="root">
<p>{{ message }}</p>
<input v-model="message" />
</div>
02
计算属性
可以通过它定义一个新属性,该属性可以结合任意多个属性,并做相关转换操作。
- 计算属性的值会基于它的依赖进行缓存,如果依赖未改变是不会重新计算的。
- 计算属性真正用于应用中时,才会进行计算。
computed: {
notePreview () {
// Makedown渲染为HTML返回
return marked(this.content)
}
}
显示HTML内容
可以使用v-html指令做HTML插值,需要注意避免XSS攻击
<div v-html="notePreview"></div>
v-text形同典型的文本插值,会对HTML标签做转义处理
侦听器watcher
watch: {
// 侦听content属性
content: {
// 处理函数
handler(val, oldVal) {
// ...
},
}
}
另外还有两个选项:
- deep,布尔类型,会以递归方式侦听嵌套对象内部值的变化。
- immediate,布尔类型,会立即触发调用处理函数,而不用等到属性值第一次变化时才调用。
复用方法
可复用函数可以写在:methods中
methods: {
saveNote(val) {
localStorage.setItem('content', val);
}
}
访问Vue实例
可以使用this访问Vue实例上的属性和方法
生命周期钩子
- beforeCreate:vue实例被创建时(如new Vue({}))、完成其他事项之前调用
- created:实例准备就绪之后调用。此时实例还没有挂载到DOM中
- beforeMount:挂载实例到Web页面之前调用
- mounted:实例被挂载到页面并且DOM可见时调用
- beforeUpdate:当实例需要更新时(一般来说,是当某个数据或计算属性发生改变时)调用
- updated:在把数据变化应用到模板之后调用。注意此时DOM可能还没有更新。
- beforeDestroy:在实例销毁之前调用
- destroyed:在实例完全销毁之后调用
例如初始化:
created() {
this.content = localStorage.getItem('content');
}
用v-on实现按钮的单击事件
<button v-on:click="callback">
简写
<button @click="callback">
用v-bind绑定属性
<button v-bind:title="notes.length + ' note(s) already'">
简写
<button :title="notes.length + ' note(s) already'">
用v-for显示列表
<div v-for="item of items">{{ item.title }}</div>
也可以使用关键字in
<div v-for="item in items">{{ item.title }}</div>
动态CSS类
<div :class="['one', 'two', 'three']">
=>
<div class="one two three">
<div :class="{ one: true, two: false, three: true }">
=>
<div class="one three">
建议将非动态的类放到静态属性中,因为Vue会对静态值做优化处理
<div class="static" :class="{ two: false, three: true }">
条件模板v-if
<div v-if="loading">
此外还有v-else和v-else-if,也很好理解
template标签
template标签不会出现在DOM中,可以对实际元素进行包裹
<template v-if="loading">
<div>
<div>
</template>
过滤器
主要用于模板内部,在数据展示之前或者传递给一个属性之前对其进行处理。
注册
Vue.filter('date', time => moment(time)
.format('DD/MM/YY, HH:mm'))
使用
{{ time | date }}
03
模板选项
new Vue({
name: 'app',
el: '#root',
template: `<div id="#app">
Hello world!
</div>`
})
并不在之前的#root中嵌入模板
组件
组件是Vue应用的核心概念,是视图的一个个小部分。采用组件构建应用有助于应用的维护和升级,这已经成为了高效、可控地开发大型Web应用的标准方法。
组件有全局组件和局部组件。使用全局函数Vue.component()可以注册全局组件
Vue.component('top-bar', {
template: `<div class="top-bar">
Top bar
</div>`,
})
使用
new Vue({
template: `<div id="#app">
<top-bar />
</div>`,
})
其实每个组件都是Vue实例,Vue利用我们为top-bar组件提供的定义创建了Vue实例。
使用prop进行父组件到子组件的通信
将prop添加到组件中
Vue.component('top-bar', {
props: ['currentPlayerIndex'],
})
使用v-bind简写语法将应用的数据绑定到prop值上
<top-bar :current-player-index="currentPlayerIndex" />
建议对prop的名字使用短横线命名方法,而在JavaScript代码中使用驼峰式命名方法。
在top-bar组件中使用prop,用法和使用数据属性一样。
Vue.component('top-bar', {
props: ['currentPlayerIndex'],
template: `<div class="top-bar">
{{ currentPlayerIndex }}
</div>`
});
在组件上监听原生事件
Vue针对组件有自己的事件系统,叫做“自定义事件”。为了监听到组件的click事件,需要对v-on指令使用.native修饰符
<card @click.native="handlePlay" />
使用自定义事件进行子组件到父组件的通信
在组件内部,使用$emit这个特殊方法触发的事件可以被父组件捕获到。该方法接收一个固定的参数,即事件类型:
this.$emit('play')
在同一个vue实例中,可以使用$on监听自定义事件
this.$on('play', () => {
console.log('event');
})
同时,$emit还会触发事件到父组件中,父组件可以使用v-on指令监听该事件
<card v-on:play="handlePlay" />
简写
<card @play="handlePlay" />
传参
this.$emit('play', 1, 2)
动画过渡效果
使用CSS过渡,结合特殊的<transition>
组件,使用v-if或v-show指令来帮助过渡。
<transition>
<hand v-if="!show" />
</transition>
当元素被添加到DOM时(进入阶段),<transition>
组件会自动将下列CSS类应用到元素中。当然,过渡阶段也有相应的事件可以监听。
- v-enter-active:进入过渡状态被激活时,在元素插入DOM之前,并在动画结束时移除它。应该在该类中添加transition css属性并定义其过渡时长。
- v-enter:进入过渡的开始状态。在元素插入DOM之前,添加该类到元素中,同时在元素被插入的下一帧移除。例如,你可以在这个类中设置透明度。
- v-enter-to:元素进入过渡的结束状态。在元素插入DOM后的下一帧添加,同时v-enter被移除。当动画完成后,v-enter-to会被移除。
当元素从DOM中移除时(离开阶段),<transition>
组件会自动将下列CSS类应用到元素中。
- v-leave-active:离开过渡状态被激活时,会应用该类。当离开过渡触发时,添加该类到元素中,并在DOM中移除元素时移除它。应该在该类中添加transition css属性并定义其过渡时长。
- v-leave:被移除的开始状态。当离开过渡触发时,添加该类到元素中,并在下一帧移除。
- v-leave-to:元素离开过渡的结束状态。在离开过渡触发后的下一帧添加,同时v-leave被移除。当DOM中移除元素时,该类也会被移除。
注:在离开阶段,并不会立即从DOM中移除元素。当过渡结束后,才会将其移除,这样用户可以看到动画效果。
一个基本的淡出动画效果
.hand.v-enter-active,
.hand.v-leave-active {
transition: opacity 1s;
}
.hand.v-enter,
.hand.v-leave-to {
opacity: 0;
}
由于可能需要复用这个动画,我们可以给它取个名字
<transition name="fade">
<hand v-if="!show" />
</transition>
需要修改css类
.hand.fade-enter-active,
.hand.fade-leave-active {
transition: opacity 1s;
}
.hand.fade-enter,
.hand.fade-leave-to {
opacity: 0;
}
另外一个特殊的组件<transition-group>
。当元素被添加、移除或移动时,该组件将对它的子元素做出动画效果。
<transition-group>
<div v-for="item of items" />
</transition-group>
transition-group默认情况下会作为span元素出现在DOM中。当然,也是可以修改的。
<transition-group tag="ul">
<div v-for="item of items" />
</transition-group>
特殊的key属性
当Vue更新存在于v-for循环中的DOM列表中,会尽量最小化DOM操作。尽可能的复用元素,并对DOM中需要修改的地方进行小范围修改。这意味着重复的元素会被打包到一起,不会在添加和移除列表中的项时移动它们。这也意味着对其应用过渡不会有动画效果。这时候就需要用key属性为元素指定唯一标识符。
<div v-for="item of items" :key="item.id"/>
使用插槽分发内容
我们使用slot元素可以将额外的布局和逻辑封装到overlay组件中,并且添加任意内容进去。
Vue.component('overlay', {
template: `<div class="overlay" @click="handleClick">
<div class="content">
<slot />
</div>
</div>
`
})
使用
<overlay>
content
</overlay>
componennt组件
可以把其转换为任意组件
<component is="h1"></component>
<component is="overlay" />
在script标签中编写模板
当定义组件时,使用这个ID引用模板即可。
<script type="text/x-template" id="banner">
<div></div>
</script>
04
接下来介绍一个更接近实际使用的开发模式。
vue-cli
可以帮助我们创建vue工程
npm i -g vue-cli
安装完成后执行vue list
可以列出官方项目模板
主要有3种类型:
- simple:不使用构建工具
- webpack: 使用webpack(推荐)
- browserify: 使用browserify
我们使用webpack-simple,并逐步引入功能
vue init webpack-simple demo
这个模板具有最小可用的webpack配置。
创建应用
添加入口文件
import Vue from "vue";
new Vue({
el: "#app",
render: h => h("div", "hello world")
});
运行应用
npm run dev
配置Babel
默认的babel配置使用名为env的Babel预设,支持ES2015以来所有稳定的js版本,还有一个stage-3的Babel预设,支持即将推出的js特性,如async/await。
我们需要再添加一个,支持JSX。并且还需要包含Babel提供的polyfill,以便Promise和Generator等新特性可以在旧版浏览器中运行。
npm i -D babel-preset-vue babel-polyfill
在.babelrc文件中添加vue预设
{
"presets": [
["env", { "modules": false }],
"stage-3",
"vue"
]
}
在src/main.js中添加
import "babel-polyfill"
更新依赖
如果需要更新依赖,可以进行如下操作
- 手动更新
检查是否有新版本npm outdated
Wanted是兼容的版本号。手动更新修改一下package.json文件中的版本号在重新安装一下包即可。
- 自动更新
npm update
会更新最新的兼容版本
构建生产环境资源文件
npm run build
单文件组件
广泛应用于实际开发,它包含3种类型的根块:
- template
- script
- style
JSX
是一种有助于编写渲染函数的语法,也可以采用。
样式
- 有作用域的样式(scoped)
<style scoped>
</style>
原理是会有特殊的属性添加到了模板元素上,使得选择器只会匹配这个组件的模板。
添加预处理器
lang属性可以指定预处理器语言(sass、less、Stylus)
<style lang="sass" scoped>
</style>
组件内的组件
import Movie from './Movie.vue';
export default {
components: {
Movie,
}
}
05
Vue插件vue-router
import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
使用router-view进行布局
它将渲染匹配当前路由的组件
<template>
<div class="app-layout">
<header></header>
<router-view />
</div>
</template>
创建路由
import Home from './components/Home.vue'
import FAQ from './components/FAQ.vue'
const routes = [
{ path: '/', name: 'home', component: Home },
{ path: '/faq', name: 'faq', component: FAQ }
]
路由名称name是可选的,方便在路由时不会导致链接失效。
路由器对象
创建路由器对象
const router = new VueRouter({
routes,
})
export default router;
导入
import router from './router';
import AppLayout from './components/AppLayout.vue'
new Vue({
el: "#app",
render: h => h(AppLayout),
router,
})
路由模式
有hash(默认)、history、abstract。
hash与任何浏览器和服务器都兼容
history 浏览器需要支持HTML5 API。服务器必须配置为当访问如/faq时发送主页,而不是404。
abstract 可以在任何JavaScript环境中使用(包括Node.js)。如果没有可用的浏览器API,将被迫使用该模式。
路由器链接
<router-link to="/faq">FAQ</router-link>
或
<router-link :to="{ name:'faq' }">FAQ</router-link>
组件默认会使用router-link-active CSS类,你可以使用它改变激活时的样式。
exact 可以设置路径完全匹配
<router-link :to="{ name:'faq' }" exact>FAQ</router-link>
发送后端请求
vue官方推荐使用axios,初始渲染可以在created生命周期中发送后端请求,再设置相应组件里的data。(接入vuex后,数据可以由vuex来管理)。
async created() {
try {
this.loading = true;
const res = await axios.get('url..');
if (res.ok) {
this.questions = res.data;
} else {
...
}
} catch (e) {
...
}
this.loading = false;
}
用自己的插件扩展Vue
请求服务器数据的功能是自定义Vue插件的好例子。
创建一个插件,只有一个规则,插件应该是一个带有install方法的对象,该方法接受Vue构造函数作为第一个参数以及一个可选的options参数。然后,该方法通过修改构造函数为框架添加新特性。
这里,我们的插件将在所有组件上添加一个$fetch的特殊方法
let baseUrl = '';
export default {
install (Vue, options) {
baseUrl = options.baseUrl;
Vue.prototype.$fetch = $fetch
}
}
export async function $fetch (method, url) {
const res = await axios[method](`${baseUrl}${url}`);
if (res.ok) {
return res.data;
} else {
throw new Error('error');
}
}
使用mixin复用代码
mixin可以在多个组件中复用组件定义(如计算属性、方法或侦听器)
mixin是可应用于其他定义对象(包括其他mixin)的组件定义对象。它看起来和普通组件定义完全一样。
Vue会自动合并标准选项,如钩子、数据、计算属性、方法和侦听器,最后应用的那个将覆盖之前的那些。组件自有选项最终合并。
export default {
data () {
return {
remoteDataLoading: 0,
}
}
}
<script>
import RemoteData from '../mixins/RemoteData'
export default {
mixins: [
RemoteData,
],
...
}
</script>
指定prop的更多细节
<script>
export default {
props: {
title: {
type: String,
required: true,
}
}
}
</script>
v-bind的prop修饰符
可以直接设置DOM节点的属性。而不是HTML属性。适合在处理输入框元素的属性(如value)中使用。
<input :value.prop="value" />
v-model
可实现数据与视图的双向绑定
<input v-model="value" />
默认使用的value prop和input事件。
路由跳转
this.$router.push({name: 'home'});
路由类型
我们可以有不同类型的路由
- 公开路由(都可以)
- 私有路由(仅登录用户)
- 访客路由(仅未登录用户)
路由元属性
路由的类型可以添加在路由的meta属性中
{ path: '/tickets', ... , meta: { private: true } }
路由器导航守卫
当路由变化时会调用函数钩子,它们可以改变路由器的行为。
router.beforeEach((to, from, next) => {
if (to.meta.private && !state.user) {
next({
name: 'login',
params: {
wantedRoute: to.fullPath,
}
});
return;
}
next();
})
在login组件中使用wantedRoute参数重定向
this.$router.replace(this.$router.params.wantedRoute || { name: 'home' })
router.replace和push的区别是将当前条目替换为新路由,而不是添加条目。
嵌套路由
const routes = [
{
path: '/tickets',
component: TicketsLayout,
children: [
{
path: '',
name: 'tickets',
component: Tickets
},
{
path: 'new',
name: 'new-ticket',
component: newTicket
}
]
}
]
对于嵌套路由,导航守卫中的条件需要修改:
router.beforeEach((to, from, next) => {
if (to.matched.some(r => r.meta.private) && !state.user) {
}
if (to.matched.some(r => r.meta.guest) && state.user) {
}
})
绑定属性
$attrs特殊属性,可以获取组件上所有非prop属性作为对象。
<FormTextArea rows="4">
<textarea
...
v-bind="$attrs"
>
动态路由
/tickets/:id -> /tickets/abc -> { id: 'abc' }
/tickets/:id/components/:comId -> /tickets/abc/components/42 -> { id: 'abc', comId: '42' }
router.params中可以获取动态参数
404页面
放置路由的最后
const routes = [
...
{
path: '*',
component: NotFound
}
]
滚动行为
history模式允许我们在路由改变时管理页面滚动。
路由改变时滚动到页面的顶部:
const router = new VueRouter({
routes,
mode: 'history',
scrollBehavior(to, from, savedPosition) {
return { x: 0, y: 0 }
},
})
每次滚动到<h1>
元素
return { selector: 'h1' }
更完善的
if (savedPosition) {
return savedPosition
}
if (to.hash) {
return { selector: to.hash }
}
return { x: 0, y: 0 }
06
使用Vuex进行状态管理
Vuex可以让我们使用一个集中式store来管理应用的全局状态。
- 为什么使用集中式的状态管理
随着组件之间的联系越来越复杂,太多的组件需要同步数据,应用的状态变得难以控制。Vuex从Flux获得灵感。Flux由一系列指导原则构成,阐明了如何使用集中式store来实现组件之间的单向数据流,可以很容易地推算出应用的逻辑和流程,从而极大地提升应用的可维护性。
Vuex store
Vuex的核心元素是store,它是一个特殊的对象,允许你将应用中的数据集中在一个设计良好的模型中。
store包含如下信息:
state,存储应用状态的响应式数据对象
getter,等价于store的计算属性
mutation,用来改变应用状态的函数
action,通常用来调用异步API的函数,然后使用mutation改变数据。
下面我们来创建一个store来熟悉这些概念。
安装Vuex插件
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
使用Vuex.Store构造函数创建store
const store = new Vuex.store({
// TODO 选项
});
在应用中注入store
import store from './store';
new Vue({
...App,
el: '#app',
router,
store,
})
现在可以在所有组件中使用$store这个特殊的属性来访问store了。
state是唯一数据源
Vuex的第一个原则就是,state是共享数据的唯一数据源。state是store的主要组成部分,它展示了应用中组件的所有共享数据。
我们在state中添加一个user属性
const store = new Vue.Stroe({
state() {
return {
user: null,
}
},
})
state是只读的,您不应该直接修改它。改变状态的唯一途经就是通过mutation,这样可以让共享状态易于预测。
读取状态
<template>
...
</template>
<script>
export default {
computed: {
user () {
return this.$store.state.user
}
}
}
</script>
使用mutation修改状态
const store = new Vuex.Store({
state () { /* ... */ },
mutations: {
user: (state, user) => {
state.user = user;
},
},
})
使用commit方法触发mutation处理函数
store.commit('user', userData);
严格模式
mutation的同步特性是出于调试的目的,可以借助开发者工具生成快照方便地调试应用。为了避免在mutation中使用异步调用,你可以在开发环境开启严格模式:
const store = new Vuex.Store({
strict: process.env.NODE_ENV !== 'production',
// ...
})
调试利器——时间旅行
使用Vuex你可以结合devtools追踪状态的每一次修改,这将极大地提升你的调试效率。
使用getter计算和返回数据
可以将getter看成store的计算属性
const store = new Vuex.Store({
// ...
getters: {
user: state => state.user,
},
})
可以使用getter代替之前直接获取状态的方法:
user () {
return this.$store.getters.user
},
我们使用getter,它可以让你在修改获取数据的方式时无需修改使用此数据的组件。
使用action操作store
action不仅可以提交mutation,还能做异步操作。
action的处理函数接受两个参数:
- context,它提供commit、dispatch、state以及链接到store的getters工具函数
- payload,它是dispatch分发时带上的参数
创建action
const store = new Vuex.Store({
// ...
actions: {
logout ({ commit }) {
commit('user', null);
}
}
})
分发action
store.dispatch('action-type', payload);
你应该总是使用action而不是mutation。因为修改action中的代码会比修改组件中的代码更好,要把action看成应用逻辑的抽象。
辅助函数
Vuex还提供了辅助函数mapGetters和mapActions,它帮我们生成了相应的getter计算属性和action方法。辅助函数的参数可以是以下两者之一:
- 类型的数组,其中的每一个元素对应于组件中的同名数据
- 对象,其中的键是组件中数据的别名,值则是类型
例如:
mapGetters(['a', 'b'])
等价于
{
a () { return this.$store.getters.a },
b () { return this.$store.getters.b },
}
mapGetters({ x: 'a', y: 'b' });
等价于
{
x () { return this.$store.getters.a },
y () { return this.$store.getters.b }
}
让我们在组件中使用它吧
import { mapGetters, mapActions } from 'vuex';
export default {
computed: mapGetters([
'user',
]),
methods: mapActions({
logout: 'logout',
}),
}
同步store和路由
import { sync } from 'vuex-router-sync';
sync(store, router);
你可以使用state.router对象获取当前路由信息,还可以使用时间旅行调试它。
Vuex模块
我们可以将状态划分为不同的模块,以便更好地管理。模块和store很像,store和其中的每一个模块都可以包含任意数量的模块,如何组织出最有利于项目的store模块结构需要你来斟酌。
// maps.js
export default {
namespaced: true,
state () {
return {
center: {},
}
}
}
import maps from './maps';
const store = new Vuex.Store({
// ...
modules: {
maps,
},
})
你可以通过store.state.maps使用这个模块。
带命名空间的模块
上面模块中的namespaced选项告诉Vuex在该模块的所有getter、mutation和action前添加maps命名空间。
mapGetters({
center: 'maps/center',
})
也可以指定命名空间
...mapGetters('maps', [
'center'.
'zoom',
]),
还可以使用createNamespacedHelpers生成基于某个命名空间的辅助函数:
import { createNamespacedHelpers } from 'vuex';
const { mapGetters } = createNamespacedHelpers('maps');
export default {
computed: mapGetters([
'center',
])
}
访问全局元素
你可以在命名空间模块的getter中访问到根getter(即所有的getter)
myAction ({ dispatch, commit, getters, rootGetters }) {
getters.a // store.getters['map/a']
rootGetters.a // store.getters['a']
commit('someMutation') // 'maps/someMutation'
commit('someMutation', null, { root: true }) // 'someMutation'
dispatch('someAction') // 'maps/someAction'
dispatch('someAction', null, { root: true }) // 'someAction'
}
使用JavaScript渲染函数编写视图
大多数情况下使用模板就够了,但你也可能遇到需要使用JavaScript完整编程能力来编写组件界面的情况。
Vue.component('my-title', {
props: ['level'],
render (h) {
return h(
`h${this.level}`,
this.$slots.default,
)
}
})
JSX
JSX语言是为了在render函数中编写更类似于HTML形式的代码。
export default {
props: ['message'],
render (h) {
return <p class="content">
{ this.message }
</p>
}
}
在JSX中,首字母大写很重要。
import LocationInfo from './LocationInfo.vue';
export default {
render (h) {
return <LocationInfo />
}
}
更完善的vuex结合方式
<script>
import { createNamespacedHelpers } from 'vuex';
const {
mapGetters: postsGetters,
mapActions: postsActions
} = createNamespacedHelpers('posts')
export default {
computed: {
...postsGetters([
'draft',
]),
title: {
get() {
return this.draft.title
},
set(value) {
this.updateDraft({
...this.draft,
title: value,
})
}
}
},
methods: {
...postsActions([
'updateDraft'
])
}
}
</script>
分发无命名空间的action
setBounds ({ dispatch }, value) {
dispatch('posts/fetchPosts', {
mapBounds: value,
}, {
root: true,
})
}
作用域插槽
我们可以通过插槽将属性传递给外部视图
<template>
<div class="search">
<slot :result="results" />
</div>
</template>
<script>
export default {
computed: {
results () {
return /* ... */
},
},
}
</script>
<Search>
<template slot-scope="props">
<div>{{ props.result.length }} results</div>
</template>
</Search>
还可以结合循环使用
<slot v-for="r of results" :result="r" />
<Search>
<div slot-scope="props" class="result">{{props.result.label}}<div>
</Search>
函数式组件
每个组件实例在创建时都需要做一些设置,比如数据响应系统、组件生命周期等。函数式组件自身没有状态(无法使用this关键字),也不会在开发者工具中显示。但在速度更快、使用内存更少。
export default {
functional: true,
render (h, { props, children }) {
return h(`h${props.level}`, children)
}
}
使用模板
<template functional>
<div class="my-component">{{ props.message }}</div>
</template>
使用PostCSS为CSS自动添加前缀
为CSS自动添加前缀可以提高样式对浏览器的兼容性。PostCSS是一个专门用于CSS后处理的库。它拥有一个非常模块化的架构,通过添加插件来使用各种方式处理CSS。PostCSS不需要额外安装,vue-loader中已经包含了它,我们只需要按需安装插件即可,我们需要安装autoprefixer这个包。
在根目录添加postcss.config.js配置
module.exports = {
plugins: [
require('autoprefixer'),
],
}
这样autoprefixer就会自动处理我们的CSS代码。
通过ESLint提升代码质量和风格
ESLint提供了一系列可以开启和关闭的lint规则,有助于保持源代码的整洁性和一致性。
命令行ESLint
eslint --ext .js, .jsx, .vue src
在Webpack中使用ESlint
添加一条新的ESLint加载器规则。
"module": {
"rules": [
{
"test": /\.(jsx?|vue)$/,
"loader": "eslint-loader",
"enforce": "pre"
}
]
}
Jest单元测试
我们需要都重要的代码进行单元测试,推荐使用Jest。
国际化
可以使用vue-i18n
服务端渲染(SSR)
配置较多,这里不赘述。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。