Vue 进阶

Vue进阶

1.1 安装vue-cli 脚手架

  • Vue 提供了一个官方的 CLI,为单页面应用快速搭建 (SPA) 繁杂的脚手架。它为现代前端工作流提供了 batteries-included的构建设置。只需要几分钟的时间就可以运行起来并带有热重载、保存时 lint 校验,以及生产环境可用的构建版本。
  • 需要安装 Node 环境,Node安装地址:http://nodejs.cn/download/,注意:安装 vue-cli 脚手架目前需要 4.0以上的 Node 版本。

1.1.1 vue-cli 全局安装

  • 在本地终端根目录执行以下命令
    npm i -g vue-cli //-g是全局安装,只要安装了在电脑任何地方都可以使用脚手架
  • 安装完成以后 可以输入命令 :vue 回车,可以看到针对vue的命令行:

1.1.2 初始化项目

  • 执行以下命令初始化项目
    vue init webpack demo //demo 是你新建项目的名称 ,也是文件名称

  • 执行之后将会自动初始化一个文件夹 :demo

  • 默认的直接回车,Yes的直接输入y回车,No的输入n回车。最后再按回车进行初始化

  • 成功以后就会创建完成一个项目模板

1.1.3 启动项目

  • 执行以下命令启动项目
    npm run dev

1.1.4 Vue 调试工具 Vue-devtools

1.1.4.1 在线安装

1.1.4.2 本地安装

谷歌右上角菜单 - 更多工具 - 扩展程序 - 开发者模式打开 - 加载已解压的扩展程序 - 导入本地文件 - 成功以后显示以下图标

  • 点击详细信息,勾选上允许访问文件网址,重启浏览器。F12打开控制台,有Vue一项表示安装成功

1.2 项目目录介绍

1.2.1 build

  • webpack 配置相关
  • 可以在此目录下的 webpack.base.conf 中的 resolve 中的 extentions 设置导入包时可以省略的文件的后缀名的类型
  • 可以在此目录下的 webpack.base.conf 中的 resolve 中的 alias 设置文件路径别名,比如 src 就可以简写为 @

1.2.2 config

  • 生产开发环境配置的参数
  • 可以在此目录下的 index.js 中的 dev属性 port 修改端口号
  • 可以在此目录下的 index.js 中的 dev属性 autoOpenBrowser 设置是否自动打开浏览器,true则自动打开

1.2.3 static

  • static 中本来是用来放置第三方资源的,默认空文件是无法上传的,如果添加上 .gitkeep 则可以将空文件上传

1.2.4 node_modules

  • 安装的第三方依赖

1.2.5 babelrc

  • 将 es6 这种高级语法转为低级语法以便于浏览器去识别

1.2.6 src

  • 做项目时写的源码,会被 webpack 进行进一步的处理打包

1.2.7 .editorconfig

  • 编辑器使用的设置

1.2.8 .eslintignore

  • 代码风格检查忽略文件

1.2.9 .eslintrc.js

  • 代码风格检查
  • rules 里面可以自定义规则

1.2.10 .gitignore

  • 使用 git 提交项目的时候忽略的一些文件

1.3 编程式导航

  • 借助于与router的实例 (this.$route)方法,通过编写代码来实现导航的切换。
    1. this.$route.back 回退一步
    2. this.$route.forward 前进一步
    3. this.$route.go 指定前进回退步数
    4. this.$route.push 导航到不同url,向history栈添加一个新的记录
    5. this.KaTeX parse error: Expected '}', got 'EOF' at end of input: …() { this.route.back() //后退一步
      },
      forwardHandle () {
      this.KaTeX parse error: Expected 'EOF', got '}' at position 27: …rd() //前进一步 }̲, goHandle (…route.go(3) //前进3步
      this. r o u t e . g o ( 3 ) / / 退 3 t h i s . route.go(-3) //后退3步 this. route.go(0) //当前导航栏刷新
      this.KaTeX parse error: Expected 'EOF', got '}' at position 30: …//超出浏览器记录无效 }̲, pushHandle…route.push(’/document’)
      this. r o u t e . p u s h ( p a t h : / d o c u m e n t ) t h i s . route.push({ path: '/document'}) this. route.push({ name: ‘document’})
      },
      replaceHandle () {
      this.$route.replace()
      }
      }

1.4 导航钩子函数

1.4.1 基本概念

  • 导航发生变化时,导航钩子主要用来拦截导航,让他完成跳转或取消

1.4.1.1 执行钩子函数的 位置

  • router 全局
  • 单个路由
  • 组件中

1.4.1.2 钩子函数

  • router 实例上:beforeEach、afterEach (只要切换导航这两个钩子函数就会立即触发)
  • 单个路由中:beforeEnter
  • 组件内的钩子:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave

1.4.1.3 钩子函数接收的参数

to:要进入的目标,路由对象,到哪里去

form:正要离开导航的路由对象,从哪里来

next:用来决定跳转或取消导航

1.4.2 beforeEach 全局钩子函数

  • 在进入导航前执行的钩子函数

1.4.2.1 用法

  • next 执行才能渲染目标导航
    router.beforeEach ( (to, form, next) => {
    next() //渲染导航
    })

1.4.2.2 阻止导航以及重定向

  • 假设 document 这个组件需要登录才能进入,我们就可以设置重定向。
  • 目标路由
    {
    path: “/document”,
    component: document,
    meta: {
    index: 3,
    login: true
    }
    }
  • 重定向,to.meta.login 是 true 则跳转到 login 组件,false 则加载目标路由组件
    router.beforeEach( (to,from,next) => {
    to.meta.login ? next(’/login’) : next()
    })

1.4.3 afterEach 全局钩子函数

  • 在进入目标路由之后执行的钩子函数
  • 目标路由
    {
    path: “/document”,
    component: document,
    meta: {
    index: 3,
    title: ‘document’
    }
    }
  • 跳转之后将目标导航的 title 改变
    router.afterEach( (to,from,next) => {
    if (to.meta.title) {
    window.document.titile = to.meta.title // 如果有 title 就将 title 赋值给网页标题
    } else {
    window.document.titile = ‘Young’ // 如果没有指定 title 就设置为默认的 Young
    }
    })

1.4.4 beforeCreate 和 beforeRouterEnter

  • beforeCreate :实例刚在内存中被创建出来,此时,还没有初始化好 data和 methods 属性。
  • beforeRouterEnter :进入路由之前,组件级钩子函数。在 beforeCreate 之前创建,因此使用 this 拿不到 data 里面的数据,但是可以通过 next 中的回调函数来调用 data 中的数据。
    beforeRouterEnter (to, from, next) {
    next( (vm)=> {
    vm.test = ‘改变了data中的数据!’
    })
    }

1.4.5 beforeRouteUpdate

  • 导航更新钩子函数,组件级钩子函数。
    beforeRouterUpdate (to, from, next) {
    next()
    }

1.4.6 beforeRouteLeave

  • 导航离开组件的钩子函数,组件级钩子函数。
    beforeRouterUpdate (to, from, next) {
    next() //如果没有 next 则不会跳转到下一个链接
    }

1.5 自定义属性 和 插件

1.5.1 自定义属性

  • 在 main.js 里面可以通过原型给 vue 自定义属性,在其他组件可以通过this访问
    Vue.prototype.$custom = “这是自定义属性”
  • 通常我们这样使用
    var obj = {
    install: function (Vue, options) {
    Vue.prototype.$custom = ‘自定义属性’
    }
    }
    Vue.use(obj,{a: 1})
    • 其中,Vue 就是我们的 Vue 构造函数,可以在里面使用原型绑定属性,options 是我们传进去的参数。

1.5.2 自定义插件

  • 我们通过以上的方式可以封装一个自己的获取 localstorage 的插件
    let local = {
    save(key, value) {
    localStorage.setItem(key,JSON.stringify(value))
    },
    fetch (key) {
    return JSON.parse(localStorage.getItem(key) || {})
    }
    }
    export default {
    install: function (Vue) {
    Vue.prototype.$local = local
    }
    }
    • 那么我们就可以在全局通过 $local 获取到这个local对象并调用下面的方法。

1.6 vuex

1.6.1 vuex 概念

  • 专门为 Vue.js 应用程序开发的 状态管理模式,采用集中式存储管理应用的所有组件的状态,以相应的规则保证状态以一种可预测的方式发生变化。
  • 状态:
    • 组件内部状态:仅在一个组件内使用的状态(data字段)
    • 应用级别状态:多个组件共用的状态
  • 什么情况下使用 vuex 多个视图:
    • 多个视图依赖同一状态
    • 来自不同视图的行为需要变更同一状态
  • 核心概念:
    • store:类似容器,包含应用的大部分状态,一个页面只能有一个 store,状态存储是响应式的,唯一途径显式的提交 mutations
    • state:包含所有应用级别状态的对象
    • getters:在组件内部获取 store 中状态的函数
    • mutations:唯一修改状态的时间回调函数(默认同步)
    • actions:包含异步操作,提交mutation改变状态
    • modules:将store分割成不同的模块

1.6.2 vuex 使用 和 定义

1.6.2.1 安装 和 导入

  • 安装 vuex 模块
    npm i vuex

1.6.2.2 导入 vuex 和 vue

  • src 目录下新建一个 store 文件夹,里面新建 index.js,在 index.js 中写入以下步骤因为要用到 vue 所以要导入 vue
    import Vue from ‘vue’
    import Vuex from ‘vuex’

  • 作为插件使用
    Vue.use(Vuex)

  • 定义容器,并且把实例暴露出去
    let store = new Vuex.Store()
    export default store

1.6.2.3 在 main.js 的 vue 中注入根实例

  • 在 main.js 中导入 store 里面的 index.js,再在 Vue 中注入。
    import store from ‘./store’

    new Vue({
      el: '#app',
      router,
      store,
      components: { App },
      template: '<App/>'
    })
    

1.6.3 vuex 基本操作

  • 下面我们做一个小案例(简易计算器加减)来熟悉Vuex的基本使用。点击对应按钮可以使中间按钮数字变换。

1.6.3.1 提交mutation

  • vuex 状态存储是响应式的,唯一途径显式的提交 mutations

  • 实现步骤

    1. 在 computed 计算属性中获取到 Vuex 中的 count 值(this.$store.state)
    2. 在 methods 中定义 add 和 reduce 两函数
    3. 将 Vuex 中 mutations 中定义的方法传过来,通过 commit 改变状态提交mutation,如果要传参,第二个参数传一个对象,在此对象中定义参数。
    4. 如果要传参,还可以直接在 commit 里面传一个对象,type 属性表示 mutaions 中定义的函数。
  • 在页面中有一个两个 button 按钮,以及一个数。我们通过点击两个按钮使这个数增加或者减小。


    <button type=“button” class=“btn btn-default” @click=“reduce”>-
    {{num}}
    <button type=“button” class=“btn btn-default” @click=“add”>+

  • store 中

    1. state 里面定义不同的状态(也就是需要改变的内容)
    2. mutations 里面定义状态函数,第一个参数为state, 可以通过 state 访问到状态里面的数据,第二个参数为组件的 commit 中传过来的参数
      let store = new Vuex.Store({
      state: {
      count: 100
      },
      mutations: {
      addIncrement(state, obj) {
      state.count += obj.n;
      },
      reduceIncrement(state, obj) {
      state.count -= obj.x;
      }
      }
      });
  • 组件

    • 在这里,我们在 commit 传递了第二个参数,这个参数可以被 store 里面的函数给获取到,同样的是第二个参数。
      computed: {
      num () {
      return this.KaTeX parse error: Expected 'EOF', got '}' at position 49: …state 里面的值 }̲ } methods:…store.commit(“addIncrement”, n: 5)
      },
      reduce () {
      // 改变状态,提交 mutation
      this.$store.commit({
      type: ‘reduceIncrement’,
      x: 2
      })
      }
      }

1.6.4 actions 异步操作

  • 以上的例子我们希望1s以后再执行,mutation只能是同步的操作,由于1s以后再提交是异步的操作,如果在mutation使用同步操作,那么重要点击按钮就会触发mutation提交,此时的值是不会发生改变的。那么我们需要使用 actions,在 actions 中定义一个 addAction 函数,参数为 context 此对象中有 commit 函数,可以使提交 actions ,参数一:mutation 中的函数,参数二:可以传递自定义参数。
    actions: {
    /* 1s以后才执行 */
    addAction (context) {
    setTimeout(() => {
    //改变状态,提交mutation
    context.commit(“addIncrement”, { n: 5 });
    }, 1000);
    }
    }
  • 然后在组件的add函数中通过 dispatch 触发 actions
    add () {
    this.$store.dispatch(“addAction”) //触发一个actions
    }
  • 如果想要多个异步执行,第一个异步语句执行完毕再执行第二个。那么:
    actions: {
    /* 1s以后才执行 */
    addAction (context) {
    setTimeout(() => {
    context.commit(“addIncrement”, {n: 5});
    context.dispatch(“textAction”,{test: ‘测试’})
    }, 1000);
    },
    textAction (context,obj) {
    console.log(obj.test);
    }
    }
  • 在这里的话context 对象下面有两个方法,那么我们可以使用 es6 的解构赋值
    actions: {
    /* 1s以后才执行 */
    addAction ({commit,dispatch}) {
    setTimeout(() => {
    commit(“addIncrement”, {n: 5});
    dispatch(“textAction”,{test: ‘测试’})
    }, 1000);
    },
    textAction (context,obj) {
    console.log(obj.test);
    }
    }

1.6.5 vuex 流程

1.6.5.1 流程图

1.6.5.2 流程

  1. Vue Components:Vue 组件。HTML页面上,负责接收用户操作等交互行为,执行 dispatch 方法触发对应 actions 进行回应。
  2. dispatch:操作行为触发方法,是唯一能执行 actions 的方法。
  3. actions:操作行为处理模块。负责处理 Vue Components 接收到的所有交互行为。包含同步/异步操作,支持多个同名方法,按照注册的顺序依次触发。向后台 API 请求的操作就在这个模块中进行,包括触发其他 actions 以及提交 mutation 的操作。该模块提供了 Promise 的封装,以支持 actions 的链式触发。
  4. commit:状态改变提交操作方法。对 mutation 进行提交,是唯一能执行 mutation 的方法。
  5. mutations:状态改变操作方法。是 Vuex 修改 state 的唯一推荐方法,其他修改方式在严格模式下将会报错。该方法只能进行同步操作,且方法名只能全局唯一。操作之中会有一些 hook 暴露出来,以进行 state 的监控等。
  6. state:页面状态管理容器对象。集中存储 Vue components 中 data 对象的零散数据,全局唯一,以进行统一的状态管理。页面显示所需的数据从该对象中进行读取,利用 Vue 的细粒度数据响应机制来进行高效的状态更新。
  7. getters:state 对象读取方法。图中没有单独列出该模块,应该被包含在了 render 中,Vue Components 通过该方法读取全局 state 对象。

1.6.6 getters 计算状态

  • getters 是 vuex 用来处理不同的计算状态的。

  • 现在我们有两个数字按钮,都可以进行加减,但是,对第二个按钮有限制条件,不能大于120。


    <button type=“button” class=“btn btn-default” @click=“reduce”>-
    {{num}}
    {{num2}}
    <button type=“button” class=“btn btn-default” @click=“add”>+

  • 这时候我们就需要用到 getters,在 store 里面给 getters 属性, 里面定义一个函数 gettersCount,参数为 state,然后书写限制条件。返回一个值。
    getters: {
    gettersCount (state) {
    return state.count < 120 ? 120 : state.count
    }
    }

  • 那么,在组件里面怎么去使用 getters 计算状态的 count 值呢。
    computed: {
    num () {
    return this.KaTeX parse error: Expected 'EOF', got '}' at position 25: …te.count }̲, num2 ()…store.getters.gettersCount
    }
    }

    • 以上代码,同样的,getters 计算状态的值使用 this.$store.getters 获取到 getters 里面的值,那此时的值就有限制条件了。然后再渲染到 button 标签里面去。

1.6.7 vuex 辅助函数

  • 辅助我们操作 vuex 的函数
    • mapState 辅助操作 vuex 中 state 的值
    • mapGetters 辅助操作 vuex 中 getters 里面的值
    • mapAction 辅助操作 vuex 中 actions 的值
    • mapMutations 辅助操作 vuex 中 mutation 提交

1.6.7.1 导入

  • 分别导入四个 vuex 辅助函数
    import {mapState, mapGetters, mapAction, mapMutations} from ‘vuex’

1.6.7.2 使用

  1. mapState
  • 通过 …mapState([‘count’]) 将 count 扩展到 computed 上,这时候要渲染 count 值就需要在页面中使用 {{count}}
    computed: {
    …mapState([‘count’])
    }
  • 如果想要使用其他名字
    computed: {
    other () {},
    …mapState({
    num: ‘count’ //这里的 count 为 vuex 中的 state 中的 count
    })
    }
  1. mapGetters
  • 同样的。将 getters 里面的值扩展到 computed 上
    computed: {
    other () {},
    …mapGetters([‘gettersCount’]), //这里的 gettersCount 为 vuex 中的 getters 中的函数
    …mapState([‘count’])
    }

3.mapAction

  • action 异步
    actions: {
    addAction(context) {}
    }
    methods: {
    …mapActions([‘addAction’]) //这里的 addAction 为 vuex 中的 actions 中的函数
    }
  1. mapMutation
  • 改变状态时,提交 mutation 相当于 commit
    mutations: {
    addIncrement(state, obj) {
    state.count += obj.n;
    },
    reduceIncrement(state, obj) {
    state.count -= obj.x;
    }
    }
    …mapMutations({
    reduce: ‘reduceIncrement’ //这里的 reduceIncrement 为 mutations 中的函数
    })
  • 这里要注意的是,如果在mutations里面传有参数,则需要在事件函数里面传参数过去
    <button type=“button” class=“btn btn-default” @click=“reduce({x: 2})”>-

1.6.8 Vuex的module模块化

  • 当不同的组件的Vuex多了以后就容易混乱,所以我们会模块化。将不同功能的模块给提出来。
    let slectModule = {
    state: {
    title: ‘’,
    },
    mutations: {
    },
    actions: {
    },
    modules: {} // 子模块还可以再嵌套子模块
    }
  • 容器,只能有一个。
  • 这时候,需要通过 modules 将子模块 selectModule 注入到 Vuex 中
    let store = new Vuex.Store({
    state: {
    count: 100,
    },
    mutations: {
    },
    actions: {
    },
    modules: {
    selectModule //将子模块 selectModule 注入到 Vuex 中
    }
    })
  • 那么,在要获取数据的时候
    获取根Vuex: this. s t o r e . s t a t e . c o u n t V u e x : t h i s . store.state.count 获取子Vuex: this. store.state.selectModule.title

猜你喜欢

转载自blog.csdn.net/xiaodingyang/article/details/87914477
今日推荐