插值操做
Mustache
(双大括号)javascript
V-once
元素只渲染一次,不会随着数据改变而改变 <h2 v-once>{{message}}</h2>
v-html
按照html格式解析 <div id="app"> <h2>{{url}}</h2>//结果是<a href="http://www.baidu.com">百度一下</a> <h2 v-html="url"></h2> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { message: '你好啊', url: '<a href="http://www.baidu.com">百度一下</a>' } }) </script>
v-text
和mustache同样 <div id="app"> <h2>{{message}}, 李银河!</h2> <h2 v-text="message">, 李银河!</h2> </div>
v-pre
<div id="app"> <h2>{{message}}</h2> <h2 v-pre>{{message}}</h2>//直接显示message </div>
v-cloak
<style> [v-cloak] { display: none; } </style> </head> <body> <div id="app" v-cloak> <h2>{{message}}</h2> </div> <script src="../js/vue.js"></script> <script> // 在vue解析以前, div中有一个属性v-cloak // 在vue解析以后, div中没有一个属性v-cloak //vue来不及渲染,直接显示源代码,加这个属性就行
绑定属性
v-bind
<img :src="imgURL" alt=""> <a :href="aHref">百度一下</a> //图片的连接src、网站的连接href、动态绑定一些类、样式 <script> const app = new Vue({ el: '#app', data: { message: '你好啊', imgURL: 'https://img11.360buyimg.com/mobilecms/s350x250_jfs/t1/20559/1/1424/73138/5c125595E3cbaa3c8/74fc2f84e53a9c23.jpg!q90!cc_350x250.webp', aHref: 'http://www.baidu.com' } }) </script>
<h2 class="title" v-bind:class="{active: isActive}">{{message}}</h2> <h2 class="title" v-bind:class="getClasses()">{{message}}</h2> <h2 class="title" :class="[active]">{{message}}</h2> <button v-on:click="btnClick">按钮</button> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { message: '你好啊', isActive: true, }, methods: { btnClick: function () { this.isActive = !this.isActive }, getClasses: function () { return {active: this.isActive} } } }) </script>
:style
<h2 :style="{fontSize: finalSize + 'px', backgroundColor: finalColor}">{{message}}</h2> <h2 :style="getStyles()">{{message}}</h2>
<div id="app"> <h2 :style="[baseStyle, baseStyle1]">{{message}}</h2> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { message: '你好啊', baseStyle: {backgroundColor: 'red'}, baseStyle1: {fontSize: '100px'}, } }) </script>
计算属性
计算属性和methods的区别:css
计算属性会进行缓存,若是屡次使用时,计算属性只会调用一次。html
computed: { // fullName: function () { // return this.firstName + ' ' + this.lastName // } // name: 'coderwhy' // 计算属性通常是没有set方法, 只读属性. fullName: { set: function(newValue) { // console.log('-----', newValue); const names = newValue.split(' '); this.firstName = names[0]; this.lastName = names[1]; }, get: function () { return this.firstName + ' ' + this.lastName } }, }
事件监听
参数问题
<div id="app"> <!--1.事件调用的方法没有参数--> <button @click="btn1Click()">按钮1</button> <button @click="btn1Click">按钮1</button> <!--2.在事件定义时, 写方法时省略了小括号, 可是方法自己是须要一个参数的, 这个时候, Vue会默认将浏览器生产的event事件对象做为参数传入到方法--> <!--<button @click="btn2Click(123)">按钮2</button>--> <!--<button @click="btn2Click()">按钮2</button>--> <button @click="btn2Click">按钮2</button> <!--3.方法定义时, 咱们须要event对象, 同时又须要其余参数--> <!-- 在调用方式, 如何手动的获取到浏览器参数的event对象: $event--> <button @click="btn3Click(abc, $event)">按钮3</button> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { message: '你好啊', abc: 123 }, methods: { btn1Click() { console.log("btn1Click"); }, btn2Click(event) { console.log('--------', event); }, btn3Click(abc, event) { console.log('++++++++', abc, event); } } }) // 若是函数须要参数,可是没有传入, 那么函数的形参为undefined // function abc(name) { // console.log(name); // } // // abc() </script>
修饰符
<div id="app"> <!--1. .stop修饰符的使用--> <div @click="divClick"> aaaaaaa <button @click.stop="btnClick">按钮</button> </div> <!--2. .prevent修饰符的使用--> <br> <form action="baidu"> <input type="submit" value="提交" @click.prevent="submitClick"> </form> <!--3. .监听某个键盘的键帽--> <input type="text" @keyup.enter="keyUp"> <!--4. .once修饰符的使用--> <button @click.once="btn2Click">按钮2</button> </div>
条件判断
key的问题
//切换类型后还会保留原来的内容,由于vue在进行dom渲染时,会复用存在的元素,而不是建立新的元素,添加不一样的能够就能解决这个问题 <div id="app"> <span v-if="isUser"> <label for="username">用户帐号</label> <input type="text" id="username" placeholder="用户帐号" > </span> <span v-else> <label for="email">用户邮箱</label> <input type="text" id="email" placeholder="用户邮箱" > </span> <button @click="isUser = !isUser">切换类型</button> </div>
<div id="app"> <span v-if="isUser"> <label for="username">用户帐号</label> <input type="text" id="username" placeholder="用户帐号" key="username"> </span> <span v-else> <label for="email">用户邮箱</label> <input type="text" id="email" placeholder="用户邮箱" key="email"> </span> <button @click="isUser = !isUser">切换类型</button> </div>
v-if和v-show的区别
v-if:条件为false,不会存在dom中vue
v-show:条件为false,会添加行内样式display:nonejava
循环遍历
遍历数组
<div id="app"> <!--1.在遍历的过程当中,没有使用索引值(下标值)--> <ul> <li v-for="item in names">{{item}}</li> </ul> <!--2.在遍历的过程当中, 获取索引值--> <ul> <li v-for="(item, index) in names"> {{index+1}}.{{item}} </li> </ul> </div>
遍历对象
<div id="app"> <!--1.在遍历对象的过程当中, 若是只是获取一个值, 那么获取到的是value--> <ul> <li v-for="item in info">{{item}}</li> </ul> <!--2.获取key和value 格式: (value, key) --> <ul> <li v-for="(value, key) in info">{{value}}-{{key}}</li> </ul> <!--3.获取key和value和index 格式: (value, key, index) --> <ul> <li v-for="(value, key, index) in info">{{value}}-{{key}}-{{index}}</li> </ul> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { info: { name: 'why', age: 18, height: 1.88 } } }) </script>
遍历时添加key
//能够高效更新虚拟dom <ul> <li v-for="item in letters" :key="item">{{item}}</li> </ul>
检查数组更新
- push()
- pop()
- shift()
- unshift()
- splice()
- sort()
- reverse()
// 1.push方法 // this.letters.push('aaa') this.letters.push('aaaa', 'bbbb', 'cccc') // 2.pop(): 删除数组中的最后一个元素 this.letters.pop(); // 3.shift(): 删除数组中的第一个元素 this.letters.shift(); // 4.unshift(): 在数组最前面添加元素 // this.letters.unshift() this.letters.unshift('aaa', 'bbb', 'ccc') // 5.splice做用: 删除元素/插入元素/替换元素 // 删除元素: 第二个参数传入你要删除几个元素(若是没有传,就删除后面全部的元素) // 替换元素: 第二个参数, 表示咱们要替换几个元素, 后面是用于替换前面的元素 // 插入元素: 第二个参数, 传入0, 而且后面跟上要插入的元素 // splice(start) // splice(start): //第二个参数:不传=删除后面全部,传3=替换3个,传0=插入的元素 this.letters.splice(1, 3, 'm', 'n', 'l', 'x') // this.letters.splice(1, 0, 'x', 'y', 'z') // 5.sort() this.letters.sort() // 6.reverse() this.letters.reverse() // 注意: 经过索引值修改数组中的元素 // this.letters[0] = 'bbbbbb'; // this.letters.splice(0, 1, 'bbbbbb') // set(要修改的对象, 索引值, 修改后的值) // Vue.set(this.letters, 0, 'bbbbbb')
双向绑定
v-model的原理
首先须要实时获取数据,那么就须要:vlalue. 而后修改数据时,同步到data.那么就须要@input方法实时把数据发到data
<div id="app"> <!--<input type="text" v-model="message">--> <input type="text" :value="message" @input="valueChange"> <!-- <input type="text" :value="message" @input="message = $event.target.value"> --> <h2>{{message}}</h2> </div> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { message: '你好啊' }, methods: { valueChange(event) { this.message = event.target.value; } } }) </script>
修饰符
<div id="app"> <!--1.修饰符: lazy--> <input type="text" v-model.lazy="message"> <h2>{{message}}</h2> <!--2.修饰符: number--> <input type="number" v-model.number="age"> <h2>{{age}}-{{typeof age}}</h2> <!--3.修饰符: trim--> <input type="text" v-model.trim="name"> <h2>您输入的名字:{{name}}</h2> </div>
组件化开发
步骤解析
- Vue.extend()建立一个组件构造器,同时传入自定义组件模板
- Vue.component()注册组件,并给他起一个标签名.因此须要传组件构造器和标签名
- 挂载Vue的实例下,不然不会生效
组件数据返回值
<div id="app"> <cpn></cpn> <cpn></cpn> <cpn></cpn> </div> <template id="cpn"> <div> <h2>当前计数: {{counter}}</h2> <button @click="increment">+</button> <button @click="decrement">-</button> </div> </template> <script src="../js/vue.js"></script> <script> // 1.注册组件 const obj = { counter: 0 } Vue.component('cpn', { template: '#cpn', // data() { // return { // counter: 0 // } // }, data() { return obj }, methods: { increment() { this.counter++ }, decrement() { this.counter-- } } }) const app = new Vue({ el: '#app', data: { message: '你好啊' } }) </script>
props基本用法
//在这里传值,message是父组件的数据对象 <cpn :cmessage="message" :cmovies="movies"></cpn> //数组中的字符串就是传递时的名称 props: ['cmovies', 'cmessage'] //这种能够设置默认值,类型 props: { // 1.类型限制 // cmovies: Array, // cmessage: String, // 2.提供一些默认值, 以及必传值 cmessage: { type: String, default: 'aaaaaaaa', required: true }, // 类型是对象或者数组时, 默认值必须是一个函数 cmovies: { type: Array, default() { return [] } } }
子组件向父组件传值
自定义事件流程 1.在子组件经过$emit()来触发事件 2.在父组件经过v-on来监听子组件的事件
<!--父组件模板--> <div id="app"> <cpn @item-click="cpnClick"></cpn> </div> <!--子组件模板--> <template id="cpn"> <div> <button v-for="item in categories" @click="btnClick(item)"> {{item.name}} </button> </div> </template> <script src="../js/vue.js"></script> <script> // 1.子组件 const cpn = { template: '#cpn', data() { return { categories: [ {id: 'aaa', name: '热门推荐'}, {id: 'bbb', name: '手机数码'}, {id: 'ccc', name: '家用家电'}, {id: 'ddd', name: '电脑办公'}, ] } }, methods: { btnClick(item) { // 发射事件: 自定义事件 this.$emit('item-click', item) } } } // 2.父组件 const app = new Vue({ el: '#app', data: { message: '你好啊' }, components: { cpn }, methods: { cpnClick(item) { console.log('cpnClick', item); } } }) </script>
组件访问
<div id="app"> <cpn></cpn> <cpn></cpn> <cpn ref="aaa"></cpn> <button @click="btnClick">按钮</button> </div> <template id="cpn"> <div>我是子组件</div> </template> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { message: '你好啊' }, methods: { btnClick() { // 1.$children console.log(this.$children); for (let c of this.$children) { console.log(c.name); c.showMessage(); } // 2.$refs => 对象类型, 默认是一个空的对象 ref='bbb' console.log(this.$refs.aaa.name); } }, components: { cpn: { template: '#cpn', data() { return { name: '我是子组件的name' } }, methods: { showMessage() { console.log('showMessage'); } } }, } }) </script>
//子组件访问父组件 //不推荐使用,耦合过高了 // 1.访问父组件$parent console.log(this.$parent); console.log(this.$parent.name); // 2.访问根组件$root console.log(this.$root); console.log(this.$root.message);
插槽slot
封装原则:保留共性,将不一样暴露为插槽ios
- 若是有多个值, 同时放入到组件进行替换时, 一块儿做为替换元素
插槽做业域
父组件替换插槽的标签,内容由子组件提供web
<div id="app"> <cpn></cpn> <cpn> <!--目的是获取子组件中的pLanguages--> <template slot-scope="slot"> <!-- <span v-for="item in slot.data"> - {{item}}</span> --> <!-- <span>{{slot.data.join(' - ')}}</span> --> </template> </cpn> </div> <template id="cpn"> <div> <slot :data="pLanguages"> <ul> <li v-for="item in pLanguages">{{item}}</li> </ul> </slot> </div> </template> <script src="../js/vue.js"></script> <script> const app = new Vue({ el: '#app', data: { message: '你好啊' }, components: { cpn: { template: '#cpn', data() { return { pLanguages: ['JavaScript', 'C++', 'Java', 'C#', 'Python', 'Go', 'Swift'] } } } } }) </script>
Webpack
导入
// 1.使用commonjs的模块化规范 const {add, mul} = require('./js/mathUtils.js') console.log(add(20, 30)); console.log(mul(20, 30)); // 2.使用ES6的模块化的规范 import {name, age, height} from "./js/info"; console.log(name); console.log(age); console.log(height); // 3.依赖css文件 require('./css/normal.css')
Vue-router
history.pushStath({},'','/home') //有历史记录 historyreplaceState({},'','/foo/bar') //没历史记录 history.back() 等价于 history.go(-1) history.forward() 则等价于 history.go(1)
使用vue-router步骤
- 建立router实例并挂载到vue实例中
- 建立路由组件
- 配置路由映射关系:组件和路径的映射关系
- 使用路由:经过<router-link>和<router-view>
router实例 import VueRouter from 'vue-router' import Vue from 'vue' import Home from '../components/Home' import About from '../components/About' //注入插件 Vue.use(VueRouter) //定义路由 const routes =[ {path:'',redirect:'/home'}, {path:'/home',component:Home}, {path:'/about',component:About} ] //建立router实例 const router = new VueRout({ routes, mode:'history', linkActiveClass:'active' }) export default router
挂载到vue实例中 import Vue from 'vue' import App from './App' import router from './router' new Vue({ el:'#app', router, render:h=>h(App) })
使用路由 <template> <div id="app"> <router-link to="/home">首页</router-link> <router-link to="/about">关于</router-link> <router-view></router-view> //能够用这种方法替代组件 //<button @click="homeClick">首页</button> //<button @click="aboutClick">关于</button> </div> </template> export default{ name:'App', methods:{ homeClick(){ //至关于pushstate this.$router.push('/home') }, aboutClick(){ this.$router.replace('/about') } } }
router-link
tag: tag能够指定<router-link>以后渲染成什么组件, 好比上面的代码会被渲染成一个<li>元素, 而不是<a> replace: replace不会留下history记录, 因此指定replace的状况下, 后退键返回不能返回到上一个页面中 active-class: 当<router-link>对应的路由匹配成功时, 会自动给当前元素设置一个router-link-active的class <router-link to="/home" tag="button" replace active-class="active">首页</router-link> <router-link to="/about" tag="button" replace active-class="active">关于</router-link>
动态路由
//router routes这么配置 { path: '/user/:id', component: User, meta: { title: '用户' }, },
//地址这么写 <router-link to="/user/123">用户</router-link>
//路由对应的组件 <h2>{{userId}}</h2> <h2>{{$route.params.id}}</h2> //这样也行 computed: { userId() { return this.$route.params.id } },
路由懒加载
//在router这么导入组件 const Home = () => import('../components/Home')
嵌套路由
步骤正则表达式
- 建立子组件,并在路由映射中配置
- 在组件内部使用<router-view>标签
{ path: '/home', component: Home, meta: { title: '首页' }, children: [ //能够配置默认路由 // { // path: '', // redirect: 'news' // }, { path: 'news', component: HomeNews }, { path: 'message', component: HomeMessage } ] },
home组件 <router-link to="/home/news">新闻</router-link> <router-link to="/home/message">消息</router-link> <router-view></router-view>
传递参数
params的类型:
配置路由格式: /router/:id 传递的方式: 在path后面跟上对应的值 传递后造成的路径: /router/123, /router/abcvue-router
query的类型:
配置路由格式: /router, 也就是普通配置 传递的方式: 对象中使用query的key做为传递方式 传递后造成的路径: /router?id=123, /router?id=abc编程
<router-link :to="'/user/'+userId">用户</router-link> <router-link :to="{path: '/profile', query: {name: 'why', age: 18, height: 1.88}}">
js方式 profileClick() { this.$router.push({ path: '/profile', query: { name: 'kobe', age: 19, height: 1.87 } }) }
获取参数
获取参数是经过$route对象获取
<h2>{{$route.query.name}}</h2> <h2>{{$route.query.age}}</h2> <h2>{{$route.query.height}}</h2> <h2>{{$route.params.id}}</h2>
route和router区别
route能够获取name,path,query,params等
routers vueRouter的实例,导航到不一样的URL就用$router.push()方法
导航守卫
导航钩子的三个参数解析: to: 即将要进入的目标的路由对象. from: 当前导航即将要离开的路由对象. next: 调用该方法后, 才能进入下一个钩子.
能够利用beforeEach来完成标题的修改
步骤
- 在路由中添加标题
- 利用导航守卫修改标题
{ path: '/about', component: About, meta: { title: '关于'//在这定义标题 }, beforeEnter: (to, from, next) => { //建立路由独享守卫 // console.log('about beforeEnter'); next() } },
// 前置守卫(guard) router.beforeEach((to, from, next) => { document.title = to.matched[0].meta.title//修改标题 // console.log('执行完这行就执行afterEach方法'); next() })
// 后置钩子(hook)不须要主动调用next()函数. router.afterEach((to, from) => { // console.log('----'); })
Keep-alive
keep-alive 是 Vue 内置的一个组件,可使被包含的组件保留状态,或避免从新渲染。
//include - 字符串或正则表达,只有匹配的组件会被缓存 //exclude - 字符串或正则表达式,任何匹配的组件都不会被缓存 <keep-alive exclude="Profile,User">//不要随便加空格 <router-view/> </keep-alive>
Promise
//普通方式 new Promise((resolve,reject){ setTimeout(()=>{ //成功执行resolve resolve('Hello World') //失败执行reject reject("error message") }) }).then((data)=>{ //处理代码 conssole.log(data) }).catch((err)=>{ //错误时执行这里 console.log(err) })
//另一种方式,resolve和reject写在then里 new Promise((resolve,reject)){ setTimeout(()=>{ //正确时执行 resolve('Hello') //错误时执行 reject('error') },1000) }.then(data=>{ console.log(data) },err=>{ console.log(err) })
//链式编程 new Promise((resolve, reject) => { setTimeout(() => { resolve('aaa') }, 1000) }).then(res => { // 1.本身处理10行代码 console.log(res, '第一层的10行处理代码'); // 2.对结果进行第一次处理 return new Promise((resolve, reject) => { // resolve(res + '111') reject('err') }) }).then(res => { console.log(res, '第二层的10行处理代码'); return new Promise(resolve => { resolve(res + '222') }) }).then(res => { console.log(res, '第三层的10行处理代码'); }).catch(err => { console.log(err); })
//普通写法 return new Promise((resolve,reject)=>{ resolve(res+'111') }) //缩写 return Promise.resolve(res+"111") //省略 return res+'111'
异步操做
普通方式 1. 发送对象 a.对象里携带参数信息 b.成功执行的方法 2.action里发起async //组件方法 updateInfo() { this.$store.dispatch('aUpdateInfo', { message: '我是携带的信息', success: () => { console.log('里面已经完成了'); } } //action方法 aUpdateInfo(context, payload) { setTimeout(() => { context.commit('updateInfo') console.log(payload.message); payload.success() }, 1000) } promise方式 1.发送参数信息 2.action返回promise对象 a.promise对象里发起async 3.在组件执行then方法 //组件方法 updateInfo() { this.$store .dispatch('aUpdateInfo', '我是携带的信息') .then(res => { console.log('里面完成了提交'); console.log(res); }) } //action方法 aUpdateInfo(context, payload) { return new Promise((resolve, reject) => { setTimeout(() => { context.commit('updateInfo'); console.log(payload); resolve('1111111') }, 1000) }) }
all方法
Promise.all([ new Promise((resolve, reject) => { setTimeout(() => { resolve({name: 'why', age: 18}) }, 2000) }), new Promise((resolve, reject) => { setTimeout(() => { resolve({name: 'kobe', age: 19}) }, 1000) }) ]).then(results => { console.log(results); })
VueX
核心概念
- State
- getters
- Mutation
- action
- module
getters
//普通写法 powerCounter(state) { return state.counter * state.counter }
//传参数写法 //在组件中这么写 <h2>{{$store.getters.moreAgeStu(12)}}</h2> //getters这么写 moreAgeStu(state) { // return function (age) { // return state.students.filter(s => s.age > age) // } return age => { return state.students.filter(s => s.age > age) } }
mutation
//不传参数写法 //在组件这么写方法 subtraction() { this.$store.commit('decrement') } //在mutation这么写 decrement(state) { state.counter-- }
//传参数写法 //在组件中这么写方法 addCount(count) { // payload: 负载 // 1.普通的提交封装 //这么写,payload就是参数 // this.$store.commit('incrementCount', count) // 2.特殊的提交封装 //若是这么写,mutation要拿到参数须要payload.参数 this.$store.commit({ type: 'incrementCount', count }) }, //在mutation中这么写 incrementCount(state, payload) { // console.log(count); state.counter += payload.count },
响应规则
//能够实时响应 Vue.set(state.info, 'address', '洛杉矶') Vue.delete(state.info, 'age') //不能够实时响应 state.info['address'] = '洛杉矶' delete state.info.age
action
没参数
//调用action方法,在组件中这么写 asyncUpdateName() { this.$store.dispatch('aUpdateName') } //action方法 aUpdateName(context) { console.log(context); setTimeout(() => { context.commit('updateName', 'wangwu') }, 1000) }
有参数时
//有参数 //在组件这么写 updateInfo() { // this.$store.dispatch('aUpdateInfo', { // message: '我是携带的信息', // success: () => { // console.log('里面已经完成了'); // } // }) this.$store .dispatch('aUpdateInfo', '我是携带的信息') .then(res => { console.log('里面完成了提交'); console.log(res); }) } //在action这么写 // aUpdateInfo(context, payload) { // setTimeout(() => { // context.commit('updateInfo') // console.log(payload.message); // payload.success() // }, 1000) // }, aUpdateInfo(context, payload) { return new Promise((resolve, reject) => { setTimeout(() => { context.commit('updateInfo'); console.log(payload); resolve('1111111') }, 1000) }) }
module
//获取a模块的state <h2>{{$store.state.a.name}}</h2> //调用a模块的mutation,getters直接调用就行,不用加模块名
Getters接收根节点的数据
getters: { fullname(state) { return state.name + '11111' }, fullname2(state, getters) { return getters.fullname + '2222' }, fullname3(state, getters, rootState) { return getters.fullname2 + rootState.counter } }
action接收根节点数据
//局部状态经过 context.state 暴露出来,根节点状态则为 context.rootState actions: { aUpdateName(context) {//也能够用对象结构aUpdateName({state,commit,rootState}){} console.log(context); console.log("iiiii"); setTimeout(() => { context.commit('updateName', 'wangwu') }, 1000) } }
axios
export function request(config) { // 1.建立axios的实例 const instance = axios.create({ baseURL: 'http://123.207.32.32:8000', timeout: 5000 }) // 2.axios的拦截器 // 2.1.请求拦截的做用 instance.interceptors.request.use(config => { // console.log(config); // 1.好比config中的一些信息不符合服务器的要求 // 2.好比每次发送网络请求时, 都但愿在界面中显示一个请求的图标 // 3.某些网络请求(好比登陆(token)), 必须携带一些特殊的信息 return config }, err => { // console.log(err); }) // 2.2.响应拦截 instance.interceptors.response.use(res => { // console.log(res); return res.data }, err => { console.log(err); }) // 3.发送真正的网络请求 return instance(config) }
Vue配置
添加别名
//vue.config.js文件 module.exports = { configureWebpack: { resolve: { alias: { 'assets': '@/assets', 'common': '@/common', 'components': '@/components', 'network': '@/network', 'views': '@/views', } } } }