vue进阶

作者: zxhnext | 来源:发表于2019-05-15 12:12 被阅读0次

    1. vuex

    image

    state是存储数据Vue Components是视图,修改state时只能通过Actions的commit调用Mutations修改或直接通过Mutations修改

    1.1 简单使用:

    const store = new Vuex.Store({
      state: {
        count: 0
      },
      mutations: {
        increment (state) {
          state.count++
        }
      }
    })
    
    store.commit('increment')
    
    console.log(store.state.count) // -> 1
    

    1.2 state 单一状态树

    computed: mapState({
        // 箭头函数可使代码更简练
        count: state => state.count,
    
        // 传字符串参数 'count' 等同于 `state => state.count`
        countAlias: 'count',
    
        // 为了能够使用 `this` 获取局部状态,必须使用常规函数
        countPlusLocalState (state) {
          return state.count + this.localCount
        }
      })
    

    1.3 getter

    有时候我们需要从 store 中的 state 中派生出一些状态,例如对列表进行过滤并计数,这时我们需要getter

    const store = new Vuex.Store({
      state: {
        todos: [
          { id: 1, text: '...', done: true },
          { id: 2, text: '...', done: false }
        ]
      },
      getters: {
        doneTodos: state => {
          return state.todos.filter(todo => todo.done)
        }
      }
    })
    // 访问
    store.getters.doneTodos // -> [{ id: 1, text: '...', done: true }]
    // mapGetters辅助函数
    import { mapGetters } from 'vuex'
    
    export default {
      // ...
      computed: {
      // 使用对象展开运算符将 getter 混入 computed 对象中
        ...mapGetters([
          'doneTodosCount',
          'anotherGetter',
          // ...
        ])
      }
    }
    

    1.4 mutation

    更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数,mutation必须是同步的。

    const store = new Vuex.Store({
      state: {
        count: 1
      },
      mutations: {
          increment (state, n) {
            state.count += n
          }
      }
    })
    // 调用
    store.commit('increment', 10)
    // mapMutations
    import { mapMutations } from 'vuex'
    
    export default {
      // ...
      methods: {
        ...mapMutations([
          'increment', // 将 `this.increment()` 映射为 `this.$store.commit('increment')`
    
          // `mapMutations` 也支持载荷:
          'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.commit('incrementBy', amount)`
        ]),
        ...mapMutations({
          add: 'increment' // 将 `this.add()` 映射为 `this.$store.commit('increment')`
        })
      }
    }
    

    1.5 action

    const store = new Vuex.Store({
      state: {
        count: 0
      },
      mutations: {
        increment (state) {
          state.count++
        }
      },
      actions: {
        increment (context) {
          context.commit('increment')
        }
      }
    })
    // 解构方式
    actions: {
      increment ({ commit }) {
        commit('increment')
      }
    }
    // 触发
    store.dispatch('increment')
    // 异步调用与多重分发
    actions: {
      checkout ({ commit, state }, products) {
        // 把当前购物车的物品备份起来
        const savedCartItems = [...state.cart.added]
        // 发出结账请求,然后乐观地清空购物车
        commit(types.CHECKOUT_REQUEST)
        // 购物 API 接受一个成功回调和一个失败回调
        shop.buyProducts(
          products,
          // 成功操作
          () => commit(types.CHECKOUT_SUCCESS),
          // 失败操作
          () => commit(types.CHECKOUT_FAILURE, savedCartItems)
        )
      }
    }
    // mapActions
    import { mapActions } from 'vuex'
    
    export default {
      // ...
      methods: {
        ...mapActions([
          'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`
    
          // `mapActions` 也支持载荷:
          'incrementBy' // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
        ]),
        ...mapActions({
          add: 'increment' // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
        })
      }
    }
    
    // 组合action
    actions: {
      actionA ({ commit }) {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            commit('someMutation')
            resolve()
          }, 1000)
        })
      }
    }
    // 现在你可以
    store.dispatch('actionA').then(() => {
      // ...
    })
    // 在另外一个 action 中也可以
    actions: {
      // ...
      actionB ({ dispatch, commit }) {
        return dispatch('actionA').then(() => {
          commit('someOtherMutation')
        })
      }
    }
    // 使用async/await
    actions: {
      async actionA ({ commit }) {
        commit('gotData', await getData())
      },
      async actionB ({ dispatch, commit }) {
        await dispatch('actionA') // 等待 actionA 完成
        commit('gotOtherData', await getOtherData())
      }
    }
    

    1.6 模块

    const moduleA = {
      state: { ... },
      mutations: { ... },
      actions: { ... },
      getters: { ... }
    }
    
    const moduleB = {
      state: { ... },
      mutations: { ... },
      actions: { ... }
    }
    
    const store = new Vuex.Store({
      modules: {
        a: moduleA,
        b: moduleB
      }
    })
    
    store.state.a // -> moduleA 的状态
    store.state.b // -> moduleB 的状态
    

    具体使用参见官网:https://vuex.vuejs.org/zh/guide/modules.html

    下面来看一个完整的例子:
    首先项目目录如下:


    image

    index.js是启动文件

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    // * as是别名的意思
    
    import * as actions from './actions'
    import * as getters from './getters'
    import state from './state'
    import mutations from './mutations'
    import createLogger from 'vuex/dist/logger' // 通过mutation修改state时会在控制台打出logger
    
    Vue.use(Vuex)
    
    const debug = process.env.NODE_ENV !== 'production' // 检测state的修改是否来源于mutation
    
    export default new Vuex.Store({
      actions,
      getters,
      state,
      mutations,
      strict: debug,
      plugins: debug ? [createLogger()] : []
    })
    

    state.js是存储数据的文件

    import {playMode} from 'common/js/config'
    import { loadSearch, loadPlay, loadFavorite } from 'common/js/cache'
    
    const state = {
      singer: {}, // 歌手列表
      mode: playMode.sequence, // 播放顺序
      searchHistory: loadSearch(), // 搜索历史
      playHistory: loadPlay(), // 播放历史
      favoriteList: loadFavorite() // 收藏内容
    }
    export default state
    
    // 状态可以是函数返回值
    

    mutation-types.js是对mutation.js的方法名字的定义

    // 存储mutation相关的字符常量
    
    export const SET_SINGER = 'SET_SINGER'
    ......
    

    mutation.js是对state进行修改

    import * as types from './mutation-types'
    
    const mutations = {
      [types.SET_SINGER](state, singer) {
        state.singer = singer
      },
      ......
    }
    
    export default mutations
    

    getters.js是state是映射,在这里可以进行一些计算操作

    // state映射,并计算state数据
    
    export const singer = state => state.singer
    
    export const currentSong = (state) => {
      return state.playlist[state.currentIndex] || {}
    }
    ......
    

    actions.js,对于需要同时修改好多个state的操作,可用actions.js封装

    export const selectPlay = function({commit, state}, {list, index}) { // 点击歌曲列表播放
      commit(types.SET_SEQUENCE_LIST, list)
      if (state.mode === playMode.random) {
        let randomList = shuffle(list)
        commit(types.SET_PLAYLIST, randomList)
        index = findIndex(randomList, list[index])
      } else {
        commit(types.SET_PLAYLIST, list)
      }
      commit(types.SET_CURRENT_INDEX, index)
      commit(types.SET_FULL_SCREEN, true)
      commit(types.SET_PLAYING_STATE, true)
    }
    ......
    

    修改数据方法:

    // 在methods中对state映射方法:
    ...mapMutations({
        setSinger: 'SET_SINGER'
    })
    
    // 然后在需要修改的地方调用方法名:
    this.setSinger(singer)
    

    取数据方法:

    // 在computed计算属性中映射方法
    
    ...mapState({
      currentCity: 'city'
    })
    
    this.singer即可取得
    

    2. mixin

    如果多个页面有相同的函数,可使用mixin.js

    export const playlistMixin = {
      computed: {
        ...mapGetters([
          'playlist'
        ])
      },
      mounted() {
        this.handlePlaylist(this.playlist)
      },
      activated() {
        this.handlePlaylist(this.playlist)
      },
      watch: {
        playlist(newVal) {
          this.handlePlaylist(newVal)
        }
      },
      methods: {
        handlePlaylist() {
          throw new Error('component must implement handlePlaylist method')
        }
      }
    }
    
    // 然后在页面内引入
    import {playlistMixin} from 'common/js/mixin'
    
    // 并在export default{}中注册
    mixins: [playlistMixin]
    

    3. <audio>在vue中的几种状态

    @play // 加载完成 
    @error // 错误状态 
    @timeupdate // 播放时间位置
    @ended // 播放结束
    

    更多可查看: http://www.w3school.com.cn/jsref/dom_obj_audio.asp

    4. 设置每个页面title

    import Vue from 'vue'
    import HelloWorld from '@/components/HelloWorld'
    import Index from '../../static/Index'
    import Router from 'vue-router'
    Vue.use(Router)
    
    const router = new Router({
      routes: [
        {path: '/', name: 'Index',meta:{title:'登陆'}, component: Index}
    
      ]
    })
    router.beforeEach((to, from, next) => {//beforeEach是router的钩子函数,在进入路由前执行
      if (to.meta.title) {//判断是否有标题
        document.title = to.meta.title
      }
      next()//执行进入路由,如果不写就不会进入目标页
    })
    export default router;
    

    5. 路由守卫

    https://router.vuejs.org/zh/guide/advanced/navigation-guards.html

    6. directive

    image.png

    参数:


    image.png

    自定义指令,参见:https://cn.vuejs.org/v2/guide/custom-directive.html

    7. jsx

    参见:https://cn.vuejs.org/v2/guide/render-function.html

    8. axios请求拦截

    import axios from 'axios'
    import router from './router';
    
    // 请求拦截
    axios.interceptors.request.use(
      config => {
        if(localStorage.wxToken) {
          config.headers.Authorization = localStorage.wxToken
        }
        return config
      },
      error => {
        return Promise.reject(error)
      }
    )
    
    // 响应拦截
    axios.interceptors.response.use(
      response => {
        return response
      },
      error => {
        const { status } = error.response
        if(status === 401) {
          alert('token过期,请重新登录')
          localStorage.removeItem('wxToken')
          router.push('/login')
        }
        // alert(error.response.data.)
        alert(error.response.data)
        return Promise.reject(error)
      }
    )
    
    export default axios
    

    9. axios的封装

    import {config} from '../config'
    import axios from 'axios';
    axios.defaults.withCredentials = true
    
    const tips = {
        1: '抱歉,出现了一个错误',
        400: '请求错误',
        401: '未登录',
        404: '请求不存在',
        405: '禁止访问',
        451: '授权过期'
    }
    // # 解构
    class HTTP{
        request({url,data={},method='GET'}){
            return new Promise((resolve, reject)=>{
                this._request(url,resolve,reject,data, method)
            })
        }
        _request(url,resolve, reject, data={}, method='GET'){
            let $HTTP;
            if(method === "GET") {
                $HTTP = axios.get(config.api_url + url, {
                    params: data
                })
            } else if(method === "POST") {
                $HTTP = axios.post(config.api_url + url, data)
            }
            $HTTP.then((res) => {
                if(res.status==200 && !res.data.error) {
                    resolve(res.data)
                }else{
                    reject()
                    const code = res.data.error.code
                    const msg = res.data.error.message
                    this._show_error(code, msg)
                }
            }).catch((err) => {
                reject()
                this._show_error(1)
            })
        }
    
        _show_error(code, msg){
            console.log(msg)
        }
    
    
    }
    
    export {HTTP}
    

    10. keep-alive

    组件缓存

    11. vue-hooks

    参考文档:https://github.com/yyx990803/vue-hooks

    demo:https://mp.weixin.qq.com/s/p2f3jsko91iGhrbtjgmt7g?utm_medium=hao.caibaojian.com&utm_source=hao.caibaojian.com

    相关文章

      网友评论

          本文标题:vue进阶

          本文链接:https://www.haomeiwen.com/subject/pabynqtx.html