v-bind:xxx
:单向绑定,可简写为:xxx
,数据只能从data流向页面。v-model:xxx
:双向绑定,v-model:value
可简写为v-model
,一般应用在表单类元素上(如input、select等),数据不仅能从data流向页面,还可以从页面流向data。v-on:xxx
:绑定事件,可简写为@xxx
,事件的回调配置在methods对象中。v-for="(item, index) in xxx" :key="yyy"
:用于展示列表数据,可遍历数组、对象、字符串(用的很少)、指定次数(用的很少)。Vue项目中主要使用v-model指令在表单input、textarea、select等元素上创建双向数据绑定。v-model本质上是语法糖,默认情况下相当于v-bind:value和v-on:input。v-model在内部为不同的输入元素使用不同的属性并抛出不同的事件:
当一个Vue实例创建时,Vue会遍历data对象中的属性,用 Object.defineProperty将它们添加到Vue实例上,并为每一个添加的属性指定一个getter/setter,在内部追踪相关依赖,在属性被访问和修改时通知变化。每个组件实例都有相应的watcher程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter被调用时,会通知watcher重新计算,从而致使它关联的组件得以更新。
:class="xxx"
xxx可以是字符串、对象、数组。:style="{fontSize: xxx}"
其中xxx是动态值。:style="[a, b]"
其中a、b是样式对象。v-if="表达式"
v-else-if="表达式"
v-else="表达式"
v-show="表达式"
key主要用在Vue的虚拟DOM算法,作为VNode的标识,在新旧nodes对比时辨识VNodes。如果不使用key,Vue会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法。而使用key时,它会基于key的变化重新排列元素顺序,并且会移除key不存在的元素。
又名生命周期回调函数、生命周期函数、生命周期钩子。是Vue在关键时刻调用的一些特殊名称的函数。生命周期函数中的this指向是vm或组件实例对象。
this.$refs.xxx.$on()
绑定;子组件使用$emit触发事件进行传值,使用$off解绑事件。Vue.prototype.$bus = this
安装全局事件总线;A组件想接收数据,则在A组件中定义事件回调函数,在mounted钩子中用this.$bus.$on()
绑定事件(最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件);B组件传递数据,则用this.$bus.$emit
触发事件传值。import pubsub from 'pubsub-js'
;A组件想接收数据,则在A组件中定义订阅回调函数,在mounted钩子中用this.pid = pubsub.subscribe()
订阅消息(最好在beforeDestroy钩子中,用pubsub.unsubscribe(pid)
去取消订阅);B组件传递数据,则用pubsub.publish()
发布消息。this.$nextTick(回调函数)
① 默认插槽
父组件中:
html结构
子组件中:
默认插槽内容...
② 具名插槽
父组件中:
html结构1
html结构2
子组件中:
默认插槽内容...
默认插槽内容...
③ 作用域插槽
理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。(games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定)
父组件中:
- {{g}}
{{g}}
子组件中:
① 初始化数据、配置actions、配置mutations,操作文件store.js
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex
Vue.use(Vuex)
const actions = {
//响应组件中加的动作
add(context, value) {
context.commit("ADD", value)
}
}
const mutations = {
//执行加
ADD(state, value) {
state.sum += value
}
}
//初始化数据
const state = {
sum: 0
}
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state
})
② 组件中读取vuex中的数据:$store.state.sum
③ 组件中修改vuex中的数据:$store.dispatch('actions中的方法名', 数据)或$store.commit('mutations中的方法名', 数据)
注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写commit。
概念:当state中的数据需要经过加工后再使用时,可以使用getters加工。
使用:
① 在store.js中追加getters配置
......
const getters = {
bigSum(state) {
return state.sum * 10
}
}
//创建并暴露store
export default new Vuex.Store({
......
getters
})
② 组件中读取数据:$store.getters.bigSum
。
① mapState方法:用于映射state中的数据为计算属性
computed: {
//借助mapState生成计算属性,对象写法
...mapState({sum: 'sum', school: 'school', subject: 'subject'})
//借助mapState生成计算属性,数组写法
...mapState(['sum', 'school', 'subject'])
}
② mapGetters方法:用于映射getters中的数据为计算属性
computed: {
//借助mapGetters生成计算属性,对象写法
...mapGetters({bigSum: 'bigSum'})
//借助mapGetters生成计算属性,数组写法
...mapGetters(['bigSum'])
}
③ mapActions方法:用于生成与actions对话的方法,即包含$store.dispatch(xxx)
的函数
methods:{
//借助mapActions生成,对象写法
...mapActions({incrementOdd: 'jiaOdd', incrementWait: 'jiaWait'})
//借助mapActions生成,数组写法
...mapActions(['jiaOdd', 'jiaWait'])
}
④ mapMutations方法:用于生成与mutations对话的方法,即包含$store.commit(xxx)
的函数
methods:{
//借助mapMutations生成,对象形式
...mapMutations({increment: 'JIA', decrement: 'JIAN'})
//借助mapMutations生成,数组形式
...mapMutations(['JIA', 'JIAN'])
}
备注:mapActions与mapMutations在使用时,若需要传递参数,则需要在模板中绑定事件时传递好参数,否则参数是事件对象。
//修改store.js
const countAbout = {
namespaced: true,//开启命名空间
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const personAbout = {
namespaced: true,//开启命名空间
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.store({
modules: {
countAbout,
personAbout
}
})
① 开启命名空间后,组件中读取state数据:
//方式一:直接读取
this.$store.state.personAbout.list
//方式二:借助mapState读取
...mapState('countAbout', ['sum', 'school', 'subject'])
② 开启命名空间后,组件中读取getters数据:
//方式一:直接读取
this.$store.getters['personAbout/firstPersonName']
//方式二:借助mapGetters读取
...mapGetters('countAbout', ['bigSum'])
③ 开启命名空间后,组件中调用dispatch:
//方式一:直接dispatch
this.$store.dispatch('personAbout/addPersonWang', person)
//方式二:借助mapActions
...mapActions('countAbout', {incrementOdd: 'jiaOdd', incrementWait: 'jiaWait'})
④ 开启命名空间后,组件中调用commit:
//方式一:直接commit
this.$store.commit('personAbout/ADD_PERSON', person)
//方式二:借助mapMutations
...mapMutations('countAbout', {increment: 'JIA', decrement: 'JIAN'})
① 安装vue-router,应用插件Vue.use(VueRouter)
。
② 编写router配置项:
//引入VueRouter
import VueRouter from 'vue-router'
//引入组件
import About from '../components/About'
import Home from '../components/Home'
//创建router实例对象,去管理一组一组的路由规则
const router = new VueRouter({
routes: [
{
path: '/about',
component: About
},
{
path: '/home',
component: Home
}
]
})
//暴露router
export default router
③ 实现切换(active-class可配置高亮样式)
④ 指定展示位置
注:
① 路由组件通常存放在pages文件夹,一般组件通常存放在components文件夹。
② 通过切换,“隐藏”了路由组件,默认是被销毁掉的,需要的时候再去挂载。
③ 每个组件都有自己的route属性,里面存储着自己的路由信息。
④ 整个应用只有一个router,可以通过组件的$router属性获取到。
① 配置路由规则,使用children配置项:
routes: [
{
path: '/about',
component: About,
},
{
path: '/home',
component: Home,
children: [ //通过children配置子级路由
{
path: 'news', //此处一定不要写:/news
component: News,
},
{
path: 'message', //此处一定不要写:/message
component: Message,
}
]
}
]
② 跳转(要写完整路径):
① 传递参数
跳转
跳转
② 接收参数:
$route.query.id
$route.query.title
① 给路由命名:
{
path: '/demo',
component: Demo,
children: [
{
path: 'test',
component: Test,
children: [
{
name: 'hello', //给路由命名
path: 'welcome',
component: Hello
}
]
}
]
}
② 简化跳转:
跳转
跳转
跳转
① 配置路由,声明接收params参数
{
path: '/home',
component: Home,
children: [
{
path: 'news',
component: News,
},
{
path: 'message',
component: Message,
children: [
{
name: 'xiangqing',
path: 'detail/:id/:title', //使用占位符声明接收params参数
component: Detail
}
]
}
]
}
② 传递参数
跳转
跳转
注意:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!
③ 接收参数
$route.params.id
$route.params.title
{
name: 'xiangqing',
path: 'detail',
component: Detail,
//第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
// props: {a: 900}
//第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件
// props: true
//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
props($route) {
return {
id: $route.query.id,
title: $route.query.title
}
}
}
News
this.$router.push({
name: 'xiangqing',
params: {
id: xxx,
title: xxx
}
})
this.$router.replace({
name: 'xiangqing',
params: {
id: xxx,
title: xxx
}
})
this.$router.forward() //前进
this.$router.back() //后退
this.$router.go() //可前进也可后退
属性 | 值 | 说明 |
---|---|---|
include | 字符串或正则表达式 | 只有名称匹配的组件会被缓存 |
exclude | 字符串或正则表达式 | 任何名称匹配的组件都不会被缓存 |
max | 数字 | 最多可以缓存多少组件实例 |
① 全局守卫
//全局前置守卫:初始化时执行、每次路由切换前执行
router.beforeEach((to, from, next) => {
if(to.meta.isAuth) { //判断当前路由是否需要进行权限控制
if(localStorage.getItem('school') === 'xxx') { //权限控制的具体规则
next() //放行
} else {
alert('暂无权限查看')
}
} else {
next() //放行
}
})
//全局后置守卫,初始化时执行、每次路由切换后执行
router.afterEach((to, from) => {
if(to.meta.title) {
document.title = to.meta.title //修改网页的title
} else {
document.title = 'vue_test'
}
})
② 独享守卫
beforeEnter(to, from, next) {
if(to.meta.isAuth) { //判断当前路由是否需要进行权限控制
if(localStorage.getItem('school') === 'xxx') {
next()
} else {
alert('暂无权限查看')
}
} else {
next()
}
}
③ 组件内守卫
//进入守卫:通过路由规则,进入该组件时被调用
beforeRouterEnter(to, from, next) {
},
//离开守卫:通过路由规则,离开该组件时被调用
beforeRouterLeave(to, from, next) {
}
mode: 'hash'
和mode: 'history'
来设置路由器工作模式,默认为hash模式。diff算法是一种通过同层的树节点进行比较的高效算法,在Vue中作用于虚拟DOM渲染成真实DOM的新旧VNode比较。