Vue脚手架
安装使用
- 运行安装脚手架
npm i vue-cli -g
- 创建vue
vue create xxx(创建的名字)
- 运行
npm run serve
关于不同版本的Vue
vue.js和vue.runtime.xxx.js的区别
- vue.js是完整版的Vue,包含核心功能+模板解析器
- vue.runtime.xxx.js是运行版的Vue,只包含核心功能,没有模板解析器
- vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render函数接收到的createElement函数去指定具体内容
ref属性
- vue中用来给元素或子组件注册引用信息(id的替代)
- 应用在html标签上是获取真实dom元素,在组件标签上是获取组件的实例对象
- 使用:
<h1 ref='xxx'></h1>
- 获取:
this.$refs.xxx
配置项props
功能:让组件接收外部传入的数据
传递数据
<Demo name='xxx'></Demo>
接收数据
- 只接收
props: ['name']
- 限制类型
props: { name: String }
- 限制类型、限制必要性、指定默认值
props: { name: { type: String, //类型 required: true, //必要性 default: 'testName' //默认值 } }
注意事项
- props只读,Vue底层会监视,不可修改,若要修改,可以复制props中的数据,在对复制的数据进行修改
- props传过来的值如果是对象类型的,修改对象中属性的值时Vue不会报错,但不推荐这么做
适用范围
- 父组件=>子组件 直接向子组件传值
- 子组件=>父组件 需要父组件先向子组件传递函数,子组件通过函数传参的方式向父组件传值
mixin混入
- 功能:把多个组件共用的配置提取成一个混入对象
- 使用:
//定义 export const xx = { data(){...} methods:{...} } //使用 //(1)局部混入: import xx from xxxx; mixins:['xx'] //(2)全局混入 Vue.mixin(xxx);
plugins插件
- 功能:用于增强Vue
- 本质:包含install方法的一个对象,install的第一个参数是Vue,第二个参数及以后是插件使用者传递的数据
- 定义插件:
对象.install = function(Vue, options){ Vue.filter(...) Vue.directive(...) Vue.mixin(...) Vue.prototype.$myMethod = function(){...} Vue.prototype.$myProperty = function(){...} }
- 使用插件:
Vue.use()
scoped样式
- 作用:让样式在局部生效,防止冲突
- 使用:
<style scoped></style>
组件化编码流程
- 拆分静态组件:组件按照功能点进行拆分,命名不要与html元素冲突
- 实现动态组件:
- 若是一个组件在用:放在组件自身
- 若是多个组件在用:放在共同的父组件上(状态提升)
- 实现交互:从绑定事件开始
组件的自定义事件
- 组件中的通信方式,适用于:子组件 => 父组件,事件的回调要在父组件中
- 绑定自定义事件
- 方法一:在父组件中
<Demo @自定义名xxx称="xxx"></Demo>
或<Demo v-on:自定义名称="xxx"></Demo>
- 方法二:在父组件中
<Demo ref="xxx"></Demo> ... mounted(){ this.$refs.xxx.$on(绑定的自定义名称, 参数) }
- 若想让自定义事件只触发一次,可以使用once修饰符或者$once方法
- 方法一:在父组件中
- 触发自定义事件:
this.$emit(绑定的自定义名称, 数据)
- 解绑自定义事件:
this.$off('aaa') //解绑一个自定义事件 this.$off(['aaa', 'bbb']) //解绑多个 this.$off() //解绑所有
- 组件上可以绑定原生dom事件(如:click),需要使用
native
修饰符<Parent ref="parent" @click.native="show"></Parent>
- 注意:通过
this.$refs.xxx.$on(绑定事件的名称,回调)
绑定自定义事件时,回调要么配置在methods中,要么使用箭头函数,防止因为this的指向出现问题
全局事件总线(GlobalEventBus)
- 一种组件间通信的方式,适用于任意组件间通信
- 安装全局事件总线:
new Vue({ ... beforeCreated(){ Vue.prototype.$bus = this; //安装全局事件总线,$bus就是当前应用的vm }, ... })
- 使用事件总线:
- 接收数据:
methods(){ //方法一 demo(data){ ... } ... mounted(){ this.$bus.$on('xxx', this.demo) } //方法二 mounted(){ this.$bus.$on('xxx', ()=>{ ... }) } }
- 提供数据:
this.$bus.$emit('xxx', 数据)
- 最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件
beforeDestroy(){ this.$bus.$off('xxx') }
消息订阅与发布(pubsub)
- 一种组件间通信的方式,适用于任意组件之间通信
- 使用:
- 安装
npm i pubsub-js
- 引入
import pubsub from 'pubsub-js'
- 接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身
methods(){ demo(data){...} ... mounted(){ //订阅类似于定时器,需要给一个名称方便销毁 this.pubId = pubsub.subscribe('xx', this.demo);//订阅消息 } }
- 提供数据:
pubsub.publish('xx',数据)
- 最好在beforeDestroy钩子中,使用
pubsub.unsubscribe(pubId)
销毁订阅
- 安装
$nextTick()
- 使用:
this.$nextTick(回调函数)
- 作用:在下一次DOM更新结束后执行其指定的回调
- 使用时间:当改变数据后,基于要更新的dom进行某些操作时,要在nextTick所指定的回调函数中执行
过渡与动画
作用:在插入、更新或移除DOM元素时,在合适的时候给元素添加样式名
注:过渡动画前提是组件|元素务必有v-if|v-show指令才可以进行过渡
使用方法
- 元素进入:
v-enter
:进入的起点v-enter-active
:进入过程中v-enter-to
:进入的终点
- 元素离开:
v-leave
:离开的起点v-leave-active
:离开过程中v-leave-to
:离开的终点
- 使用
transition
包裹要过渡的元素,并配置name属性(单个)// 可以通过appear设置节点在初始渲染的过渡 <transition name="xxx" appear> ... </transition>
- 若有多个元素需要过渡,需要使用
transition-group
,且每个元素都需要配置key值 - 可以引入外部包来增强使用效果(如:animate.css),具体的使用可以去npm官网查看
npm install animate.css
图解
脚手架配置代理
在vue.config.js中配置代理规则
方法一
- 使用:
devServer: { proxy: 'http://localhost:xxxx' }
- 优点:配置简单,请求资源时直接发给前端(8080)即可
- 缺点:不能配置多个代理,不能灵活控制请求是否走代理
- 工作方式:优先从前端资源查找,若前端资源不存在,则转发给服务器
方法二
- 使用:
devServer: { proxy: { '/api_1': { //匹配所有以api_1开头的路径 target: 'http://localhost:aaa', //代理目标的基础路径 ws: true, //用于支持websocket changeOrigin: true, //用于控制请求头中的host值(若为false,则req.get(host)获得的host为本机端口好,为true则为代理的端口号,默认为true) pathRewrite: {'^/api_1', ''} //重写路径,必写 }, '/api_2': { //匹配所有以api_1开头的路径 target: 'http://localhost:bbb', //代理目标的基础路径 ws: true, //用于支持websocket changeOrigin: true, //用于控制请求头中的host值(若为false,则req.get(host)获得的host为本机端口好,为true则为代理的端口号,默认为true) pathRewrite: {'^/api_2', ''} //重写路径,必写 } } }
- 优点:可以请求多个资源
- 缺点:比较繁琐,请求的资源地址需要加前缀
axios请求资源
使用:
//发起get请求
axios.get('url',{params:{/*参数*/}}).then(callback)
//发起post请求
axios.get('url',{/*参数*/}).then(callback)
//具体发起请求
axios({
method: 'GET', //'POST'
url: '',
params: {}, //get
data: {} //post
}).then(function(res){
console.log(res.data)
})
vue-resource插件(了解)
- 安装插件:
npm install vue-resource
- 引入:
import vueResource from 'vue-resource'; Vue.use(vueResource);
- 使用:
this.$http.get()
和axios.get()
用法一样
插槽
- 作用:让父组件可以向子组件指定位置插入html结构,是一种组件间通信的方式,适用于父组件=>子组件
- 分类:默认插槽、具名插槽、作用域插槽
默认插槽
//父组件中
<Category>
<div>html结构</div>
</Category>
//子组件中
<template>
<div>
<slot>插槽默认内容</slot>
</div>
</template>
具名插槽
//父组件中
<Category>
<template slot="xxx1">
<div>html结构</div>
</template>
<template slot="xxx2">
<div>html结构</div>
</template>
</Category>
//子组件中
<template>
<div>
<slot name="xxx1">插槽默认内容</slot>
<slot name="xxx2">插槽默认内容</slot>
</div>
</template>
作用域插槽
- 条件:数据在组件本身,但根据数据生成的结构需要组件的使用者来决定(games数组在Category组件中,但使用数据所遍历出来的结构由App组件决定)
- 使用:
//父组件
<Category>
<template scope="{games}">
<ul>
<li v-for="(g, index) in games" :key="index"></li>
</ul>
</template>
</Category>
<Category title="游戏">
<template slot-scope="{games}">
<h4 v-for="(g, index) in games" :key="index">{{ g }}</h4>
</template>
</Category>
//子组件
<template>
<div class="category">
<h3>{{ title }}分类</h3>
<slot :games="games">default</slot>
</div>
</template>
<script>
export default {
name: 'Category',
props: ['title'],
data() {
return {
games: ['LOL', 'CF', 'Rise of the Tomb', 'PUBG']
}
}
}
</script>
Vuex
概念
在Vue中实现集中式状态(数据)管理的一个Vue插件,对Vue中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间的通信方式,适用于任意组件间通信
图解
何时使用
当多个组件需要共享数据时
搭建Vuex环境
- 创建文件:
src/store/index.js
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); const actions = {}; const mutations = {}; const state = {}; export default new Vuex.Store({ actions, mutations, state })
- 在main.js创建vm时传入store配置项
import store from './store'; new Vue({ el: '#root', store, render: h => h(App) })
使用
- 组件中读取vuex中的数据:
$store.state.xxx
- 组件中修改vuex中的数据:
$store.dispatch('action中的方法名', 数据)
或$store.commit('action中的方法名', 数据)
- 注:若没有网络请求或其他业务逻辑,组件中可以直接越过actions,不写dispatch,直接写commit
- getters使用(当state中的数据需要经过加工后再使用时,可以使用getters加工)
... const getters = { xxx(state){ return state.aaa } }
4个map方法的使用
mapState
用于帮助映射state中的数据为计算属性
computed(){
// 借助mapState生成计算属性,对象写法
...mapState({sum:'sum', school:'school', subject:'subject'})
// 借助mapState生成计算属性,数组写法
...mapState(['sum', 'school', 'subject'])
}
mapGetters
用于帮助映射getters中的数据为计算属性
computed(){
// 借助mapGetters生成计算属性,对象写法
...mapGetters({func:'func'})
// 借助mapGetters生成计算属性,数组写法
...mapGetters(['func'])
}
mapActions
用于借助mapActions生成对应的方法,方法中会调用dispatch去联系actions
methods(){
// 借助mapActions生成,对象写法
...mapActions({func:'func'})
// 借助mapActions生成,数组写法
...mapActions(['func'])
}
注:使用时需要传递参数,在模板中绑定事件时传递参数,否则参数是事件对象
mapMutations
用于借助mapMutations生成对应的方法,方法中会调用commit去联系mutations
methods(){
// 对象
...mapMutations({increment:'Increment', decrement:'Decrement'})
// 数组 同上
}
注:使用时需要传递参数,在模板中绑定事件时传递参数,否则参数是事件对象
模块化+命名空间
- 目的:让代码更好维护,多种数据分类更加明确
- 修改
store.js
const a = {
namespaced: true, //开启命名空间
state: {
x: 1
},
actions: {
actionsExample(context, value){
context.commit('mutationsExample', value);
}
},
mutations: {
mutationsExample(context, value){
console.log(context, value);
}
},
getters: {
//此处的state拿到的数据是上面的state里的数据,不是全局state里的数据
gettersExample(state) {
return state.personList[0].name;
}
}
}
const store = new Vuex.Store({
modules: {
a //在vuex中使用
}
})
- 开启命名空间后,组件中读取state数据
// 方法一: 直接读取
this.$store.store.a.x
// 方法二: 借助mapState
...mapState('a', ['x'])
- 开启命名空间后,组件中读取getters数据
// 方法一
this.$store.getters['a/gettersExample']
// 方法二
...mapGetters('a', ['gettersExample'])
- 开启命名空间后,组件中调用dispatch
// 方法一 直接dispatch
this.$store.dispatch('a/actionsExample', data);
// 方法二 借助mapActions
...mapActions('a', {test:'actionsExample'})
// 若参数名和参数相同,可使用数组写法
...mapActions('a', ['actionsExample'])
- 开启命名空间后,组件中调用commit
// 方法一 直接commit
this.$store.commit('a/mutationsExample', data);
// 方法二 借助mapMutations
...mapMutations('a', {test:'mutationsExample'})
...mapMutations('a', ['mutationsExample'])