Vue2 基础知识

  • JavaScript 表达式(Expression):

    1. 表达式是可以计算并返回一个值的任何合法的 JavaScript 结构。
    2. 它们可以是一个简单的字面量(例如数字、字符串或布尔值),也可以是复杂的组合,包括算术运算符连接的操作数、函数调用、属性访问、对象和数组字面量等。
    3. 表达式总是会生成一个值,这个值可以被赋给变量、作为参数传递给函数,或者直接参与进一步的计算。
  • JavaScript 代码(Code):

    1. JavaScript 代码通常指的是一个或多个 JavaScript 语句的集合,它们共同构成了一段可执行逻辑的单元。
    2. 语句不一定要返回值,而是用来描述一系列操作,这些操作可以改变程序的状态,控制流程(如条件语句、循环语句等)。

简单来说,一个表达式会产生一个值,而一个代码块则会执行一系列操作。

MVVM

  • M: 模型(Model) : 对应 data 中的数据
  • V: 视图(View) : 模板
  • VM: 视图模型(ViewModel) : Vue 实例对象

Object.defineProperty()

  • 数据代理:通过一个对象代理对另一个对象中属性的操作(读/写)
  • 数据代理的好处:更加方便的操作数据
let per = {
  name: "张三",
  sex: "男",
};

Object.defineProperty(per, "age", {
  value: 500,
  enumerable: true, // 控制属性是否可以枚举,默认值是 false
  writable: true, // 控制属性是否可以被修改,默认值是 false,
  configurable: true, // 控制属性是否可以被删除,默认值是 false

  get() {}, // 用来获取属性值的函数(当有人读取属性时,get 函数(getter)就会被调用,且返回值
  set() {}, // 用来设置属性值的函数(当有人修改属性时,set 函数(setter)就会被调用,
});

Vue 中的数据代理

  • 基本原理:通过 Object.defineProperty()把 data 对象中的所有属性添加到 vm 上

    • 为每一个添加到 vm 上的属性,都指定一个 getter/setter

    • 在 getter/setter 中去操作(读/写) data 中对应的属性

Vue 中的事件处理

  • @click="show" === v-on:click="show($event)"

  • 事件修饰符:

    1. .stop:阻止事件冒泡
    2. .prevent:阻止默认事件
    3. .once:事件只触发一次
    4. .capture:使用事件捕获模式
    5. .self:只有 event.target 是当前操作的元素时才触发事件
    6. .passive:事件的默认行为立即执行,无需等待事件回调执行完毕
  • 按键别名:(@keyup.XXX)

    1. 回车 enter
    2. 删除 delete(捕获“删除”和“退格”键)
    3. 退出 esc
    4. 空格 space
    5. 换行 tab(需配合@keydown 使用)
    6. 上 up
    7. 下 down
    8. 左 left
    9. 右 right

计算属性 computed

  • 定义:通过已有的属性进行计算得到的新的属性
  • 优势:与 methods 实现相比,内部有缓存机制(复用),效率更高,调试方便
    • data 里面放的是属性
    • computed 里面放的是计算属性
computed: {
  fullName {
    // 当fullName属性被读取时,get() 方法会被调用,且返回值就作为 fullName 的值
    // 初次获取fullName和所依赖项发生变化时,都会调用get(依赖项指的是计算属性中所有用到的属性)
    get(){
        return this.firstName + this.lastName;
    },
     // 当fullName被修改时调用
    set(value) {
        const arr = value.split(' ')
        this.firstName = arr[0]
        this.lastName = arr[1]
    }
  },
    // 大多数情况下计算属性是不需要修改的,可以简写为
  fullName() {
    return this.firstName + this.lastName;
  }
}

监视属性 watch

  • 当被监视的属性变化时,回调函数自动调用,进行相关操作

    • 注意
      1. 监视的属性必须存在(必须在 data 里存在),才能进行监视
  • 深度监视

watch: {
  isHot: {
    deep: true, // 配置deep: true可以检测对象内部值的改变
    immediate: true, // 初始化时让handler调用一下
    handler(newValue, oldValue) {
        onsole.log('isHot被修改了', newValue, oldValue)
      }
  },
  // 如果不需要其他配置项的,可以简写成
  isHot(newValue, oldValue) {
    console.log('isHot被修改了', newValue, oldValue)
  }

}

watch 和 computed 的区别

  1. computed 存在缓存机制,当他依赖项没有变化时,不会重新执行。而 watch 每次都会执行。
  2. computed 只能是执行同步代码。而 watch 支持异步(也就是可以用 setTimeout)。
  3. computed 有返回值。而 watch 没有返回值,需要手动处理数据。

key 的作用

  • key 是给每一个虚拟 DOM 增加的唯一标识,可以根据 key 更准确、更快的找到对应的节点

VUE 检测数据变化的原理

  • VUE 是如何监测对象里面数据改变的?

    1. 遍历对象的属性
    2. 给属性添加 getter 和 setter
    3. 遇到对象嵌套问题,进行递归
  • Vue.set & this.$set

    • 用于为对象添加响应式属性
    • 语法:Vue.set( target, propertyName/index, value )
      • target:要更改的数据源(可以是对象或者数组)
      • propertyName/index:要更改的具体数据
      • value:重新赋的值
      • 注意:Vue.set 只能给 data 里的对象追加属性而不能给 data 追加
  • VUE 是如何监测数组里面数据改变的?

    1. 通过调用数组的一些方法(push, pop, shift, unshift, splice, sort, reverse)来监听数组变化,VUE 将这些方法进行了包裹
      注意:不能使用数组索引直接修改

v-cloak

  • 用于解决网速慢时 vue.js 未能加载出来,页面出现{{xxx}}的问题,配合 css 来提升用户体验
[v-cloak]{
  display: none;
}

<div v-cloak>{{name}}</div>

VUE 自定义指令

  • 需求:定义一个 v-big 指令,和 v-text 功能类似,但会把绑定的数值放大 10 倍

<span v-big="count"></span>

data: {
  count: 1
}

directives: {
  // big函数会在一开始和所绑定的数据发生改变时调用
  big(element, binding) {
    element.innerText = binding.value * 10
  }
}

生命周期

  • 挂载流程

    1. beforeCreate:无法拿到 data 中的数据和 methods 中的方法

    2. created:可以拿到 data 中的数据和 methods 中的方法

      这个时候 Vue 开始解析模版生成虚拟 DOM,但是页面还不能显示解析好的内容

    3. beforeMount:页面呈现的是未经编译的 DOM,此时对 DOM 的操作最终不生效

      这个时候内存中的虚拟 DOM 会转为真实 DOM 插入页面,所以在 beforeMount 操作的 DOM 就不奏效了

    4. mounted:页面呈现的是经过编译的 DOM,此时可以对 DOM 进行操作(一般在此时进行开启定时器、发送网络请求、订阅消息、绑定事件等操作)

  • 更新流程

    1. beforeUpdate:操作事件改变数据后,数据已更新但页面尚未与数据同步
    2. updated:页面和数据同步,保持最新
  • 销毁流程

    1. beforeDestroy:此时可以拿到 data 中的数据和 methods 中的方法,但是对数据的修改不再触发更新(一般在此时解绑事件监听器,清理定时器等)

      注意:销毁后自定义事件会失效,但是原生 DOM 事件依然有效

    2. destroyed:所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。

VUE 组件命名规范

  • 一个单词组成

    1. 首字母小写:header
    2. 首字母大写:Header
  • 多个单词组成

    1. kebab-case 命名:goods-list
    2. CamelCase 命名:GoodsList

VueComponent

  1. 组件本质是一个名为 VueComponent 的构造函数,且不是程序员定义的,是 Vue.extend 生成的
  2. 当在代码中写入<component-name/>的时候,Vue 会创建 component-name 组件的实例对象,即执行 new VueComponent(options)
    注意:每次使用 Vue.extend 返回的都是全新的 VueComponent
  3. 组件配置中this指的是 VueComponent 实例对象,new Vue(options)中this指的是 Vue 实例对象

脚手架

  • 安装脚手架
npm install -g @vue/cli
  • 创建项目
vue create my-project
  • 项目目录
├── node_modules
├── public
│   ├── favicon.ico: 页签图标
│   └── index.html: 主页面
├── src
│   ├── assets: 存放静态资源
│   │   └── logo.png
│   │── main.js: 入口文件
│   │── App.vue: 汇总所有组件
│   │── components: 存放组件
│   │   └── HelloWorld.vue
│   └── views: 存放页面
│       └── Home.vue
├── .gitignore: git 版本管制忽略的配置
├── babel.config.js: babel 的配置文件
├── package.json: 应用包配置文件
├── package-lock.json: 包版本控制文件
├── README.md: 应用描述文件
└── vue.config.js: vue 脚手架的配置文件

ref 属性

  • 应用在 HTML 标签上获取的是真实 DOM 元素,应用在组件标签上是组件实例对象(vc VueComponent)

props

  • 功能:让组件接收外部传过来的数据
export default {
  name: "GoodsList",
  data() {
    return {};
  },
  // 完整方式
  props: {
    name: {
      type: String,
      required: true,
    },
    price: {
      type: Number,
      default: 1000,
    },
  },
};

mixin

  • 功能:可以把多个组件共用的配置提取成一个混入对象
// 定义
export const mixin = {
  mounted() {
    console.log("mixin 的 mounted 被调用了");
  },
};
// 使用
import { mixin } from "../mixin";

export default {
  name: "GoodsList",
  data() {
    return {};
  },
  mixins: [mixin],
};

插件

  • 功能:用于增强 Vue
  • 本质:包含 install 方法的一个对象,install 的第一个参数是 Vue,第二个以后的参数是插件使用者传递的数据
// 定义
export default {
  install(Vue, options) {
    // 1. 添加全局过滤器
    Vue.filter(....)
    // 2. 添加全局指令
    Vue.directive(....)
    // 3. 配置全局混入(合)
    Vue.mixin(....)
    // 4. 添加实例方法
    Vue.prototype.$myMethod = function() {...}
    Vue.prototype.$myProperty = xxxx
  },
}
// 使用
Vue.use();

组件通信

  • 父传子

    • 利用 props
    1. 父组件将要传递的值或者方法通过标签属性形式传递给子组件
    2. 子组件利用 props 接收父组件传递过来的值或者方法并使用
      注意:props 是一个数组 props:[]
  • 子传父

    • 利用 props
    1. 父组件通过标签属性形式传递一个函数给子组件
    2. 子组件通过该函数将数据传递给父组件
    • 利用 $emit
    1. 父组件通过标签属性形式给子组件绑定一个自定义事件
    2. 子组件通过 $emit 触发该事件,并将数据传递给父组件
    // 父组件
    // 通过父组件给子组件绑定一个自定义事件
    <ChildComponent @getData="getChildData"></ChildComponent>
    
    methods: {
      getChildData(data) {
        console.log(data);
      }
    }
    
    // 子组件
    <button @click="sendData">点击</button>
    
    methods: {
      sendData() {
        this.$emit("getData", data);
    }},
    beforeDestroy(){
      // 通过$off解绑自定义事件
      // 解绑一个
      this.$off("getData");
      // 解绑多个
      this.$off(["getData",...]);
      // 全部解绑
      this.$off();
    }
    
    • 利用全局事件总线

自定义事件

  • 一种组件间通信的方式,适用于:子组件 ===> 父组件
  • 具体实现:见标题为 《组件通信》 的内容
  • :如果在组件中使用原生(如 @click)事件,需要写成@click.native

全局事件总线

  • 一种组件间通信的方式,适用于:任意组件间通信
  1. 在 new Vue 的时候,通过beforeCreate生命周期在 Vue 的 prototype 上绑定一个属性(随便任何名字),值为 this
new Vue({
  // ...
  beforeCreate() {
    Vue.prototype.$bus = this; // 安装全局事件总线
  },
});
  1. 在 A 组件中通过this.$bus.$on来接收数据
mounted: {
  this.$bus.$on("getData", (data) => {
    console.log(data);
  });
}
beforeDestroy() {
  this.$bus.$off("getData"); // 解绑getData事件
}
  1. 在 B 组件中通过this.$bus.$emit来发送数据
<button @click="sendMsg">发送信息</button>

data(){
  return {
    msg: "Hello World"
  }
},
methods: {
  sendMsg() {
    this.$bus.$emit("getData", this.msg);
  },
}

消息订阅与发布

  • 一种组件间通信的方式,适用于:任意组件间通信
  1. 安装pubsub-js
npm install pubsub-js
  1. 引入PubSub
import PubSub from 'pubsub-js'
  1. 使用
    注意:接收数据和发送数据的事件名称必须一致
// 在传递数据的组件中,通过`PubSub.publish`来发送数据
PubSub.publish("getMsg", { name: "curry" });
// 在接收数据的组件中,通过`PubSub.subscribe`来接收数据(一般是当该组件加载完之后就要先注册一下接收数据的事件,所以一般写在`mounted`生命周期中)
mounted() {
 this.pubId = PubSub.subscribe("getMsg", (msg, data) => {
   console.log(msg, data, "接收来的数据");
 });
},
beforeDestroy() {
 PubSub.unsubscribe(this.pubId); // 组件销毁前,一定要取消订阅
}

$nextTick

  • 语法:this.$nextTick(回调函数)

  • 官方解释:在下一次 DOM 更新结束后执行指定的回调函数

  • 自己解释:当你修改了数据之后,Vue 帮你操作完 DOM 之后,把真实的 DOM 放入页面了,Vue 再帮你调用这个函数

axios

  • 作用:发送 ajax 请求

  • 安装

npm install axios
  • 引入
import axios from 'axios'
  • vue.config.js 配置代理
module.exports = {
  // 方式1 配置单个代理
  devServer: {
    proxy: "http://localhost:3000",
  },
  // 方式2 配置多个代理
  devServer: {
    proxy: {
      "/api": {
        // 前缀 紧跟在端口号后面
        target: "http://localhost:3000", // 代理服务器地址
        pathRewrite: {
          "^/api": "", // 包含api的替换为空
        },
        ws: true, // 是否启用websockets
        changeOrigin: true, // 用户控制请求头中的host值
      },
      "/foo": {
        target: "...",
      },
    },
  },
};

插槽 slot

  • 作用:让父组件可以向子组件指定位置插入 html 结构,也是一种组件间通信的方式,适用于父组件 ===> 子组件(传递的是 html 结构)

  • 默认插槽

    1. 在父组件中传入内容
    <Category title="游戏">
      <img src="https://..." />
    </Category>
    
    1. 在子组件中定义
    <slot> 我是默认内容,当没有传入内容的时候,就展示我 </slot>
    
  • 具名插槽

  1. 在父组件中传入内容
<Category title="游戏">
  <img src="https://..." slot="img" />
  <a href="#" slot="link">点击去详情</a>
</Category>
  1. 在子组件中定义
<div>
  <slot name="img"></slot>
  <slot name="link"></slot>
</div>
  • 作用域插槽
  • 注:作用域插槽中子组件可以向父组件传数据,也就是 HTML 结构是父组件来规定,数据由子组件来提供(子组件传给父组件的)
  1. 子组件
<slot :dataSource="games"></slot>

export default {
  data(){
    return {
      games: ['红色警戒', '穿越火线', '劲舞团', '超级玛丽']
    }
  }
}
  1. 父组件
<template scope="dataSource" || scope="{games}">
  <ul>
    <li v-for="item in dataSource.games" :key="item">{{item}}</li>
  </ul>
</template>

Vuex

  • 概念:在 Vue 中实现集中式状态(数据)管理的一个 Vue 插件,对 vue 应用中多个组件共享状态进行集中式的管理
    注意 vue2 中只能使用 vuex 的 3 版本
    注意 vue3 中只能使用 vuex 的 4 版本

  • 安装及使用

  1. npm install vuex

  2. 在 src 下创建 store 文件夹,创建 index.js 文件

  3. index.js 的内容

    import Vue from "vue";
    import Vuex from "vuex";
    Vue.use(Vuex);
    
    // 准备actions - 用于响应组件中的动作
    const actions = {
      increment(context, value) {
        console.log("+++", context, value);
        context.commit("INCREMENT", value);
      },
    };
    
    // 准备mutations - 用于操作数据(state)
    const mutations = {
      INCREMENT(state, value) {
        state.count += value;
      },
    };
    
    // 准备state - 用于存储数据
    const state = {
      count: 0,
    };
    
    //准备getters - 用于将state中的数据进行加工
    const getters = {
      powerCouunt(state) {
        return state.count * state.count;
      },
    };
    
    // 创建store
    const store = new Vuex.Store({
      actions,
      mutations,
      getters,
      state,
    });
    
    export default store;
    
  4. 在 main.js 中创建 vue 实例时传入 store 对象

    import store from "./store";
    
  5. 在组件中触发

    methods: {
      handleClick() {
        this.$store.dispatch("increment", 5);
      }
    }
    
  6. 在组件中获取

    <h1>{{ $store.state.count }}</h1>
    <h1>{{ $store.getters.powerCouunt }}</h1>
    
  7. mapState

    import { mapState } from "vuex";
    
    computed: {
     // 写法一:借助mapState生成计算属性,从state中读取数据。(对象写法)
      ...mapState({shu:'count',...})
    
     // 写法二:借助mapState生成计算属性,从state中读取数据。(数组写法)
      ...mapState(['count'])
    }
    
    <h1>{{shu}}</h1>  // 写法一
    <h1>{{count}}</h1>  // 写法二
    
  8. mapGetters

  import { mapGetters } from "vuex";

  computed: {
   // 写法一:借助mapGetters生成计算属性,从getters中读取数据。(对象写法)
    ...mapGetters({zong:'powerCouunt'})

   // 写法二:借助mapGetters生成计算属性,从getters中读取数据。(数组写法)
    ...mapGetters(['powerCouunt'])
  }

  <h2>{{zong}}</h2>  // 写法一
  <h2>{{powerCouunt}}</h2>  // 写法二
  1. mapMutations
  import { mapMutations } from "vuex";

  methods: {
    // 借助mapMutations生成对应的方法,方法中会调用commit去联系mutations(推荐:对象写法)
    ...mapMutations({increment:'INCREMENT'})
  }

  <button @click="increment(3)"> + 3 </button>
  1. mapActions
  import { mapActions } from "vuex";
  // 借助mapActions生成对应的方法,方法中会调用dispatch去联系actions(推荐:数组写法)
  methods: {
   ...mapActions(['increment'])
  }

  <button @click="increment(3)"> + 3 </button>
  1. namespace
  // 第一步: 在store下的index.js中根据模块创建对象
  const countAbout = {
    namespaced: true, // 开启命名空间
    state: () => ({ ... }),
    mutations: { ... },
    actions: { ... },
    getters: { ... }
  }

  // 第二步: 将创建好的模块导出
  const store = new Vuex.Store({
    modules: {
      countAbout: countAbout,
      ...
    }
  })


  // 第三步: 在组件中使用
  <h1>{{count}}</h1>

  import { mapState } from 'vuex'
  computed: {
    // 根据namespace找对它对应的state中的数据
    // 因为数据有多个,所以用数组形式
    // 如果有多个命名空间,需要多写几个mapState
    ...mapState('countAbout',['count'])
    // ...
  }

  // 第四步: 跟命名空间相对应的mapActions、mapMutations...都需要修改
   ...mapMutations('countAbout',{increment:'INCREMENT',...})
   ...mapState('countAbout',{count:'count',...})
  1. 总结
    11.1. 用户点击按钮,调用 store.dispatch() 方法
    11.2. store.dispatch() 方法将 action 对象发送给 store
    11.3. store 中的 action 调用对应的 mutations 中的方法,来操作 store 中的 state
    11.4. mutations 中的方法完成并重新渲染页面

    注意:
    11.5. 如果点击按钮后的操作没有任何逻辑,可以直接通过 commit 调用 mutations 中的方法来修改 state
    11.6. 如果当前一个 action 的操作和逻辑过多,可以通过调用 context.dispatch()继续执行其他 action
    不成文的规定:
    11.7. actions 中的方法和 mutations 中的方法名最好相同,但是 mutations 中的方法名最好写成大写

路由

注意 vue2 中只能使用 vue-router3 版本
注意 vue3 中只能使用 vue-router4 版本

  • 安装及使用
  1. npm install vue-router@3
  2. 在 src 下创建 router 文件夹,创建 index.js 文件
  3. index.js 的内容
import VueRouter from "vue-router";

import Home from "../pages/Home";
import About from "../pages/About";
import Message from "../pages/Message";

const router = new VueRouter({
  routes: [
    {
      path: "/home",
      component: Home,
    },
    {
      path: "/about",
      component: About,
      children: [
        {
          path: "message", // 路由嵌套时,子级路由中的path不要加斜线( / )
          component: Message,
        },
      ],
    },
  ],
});
export default router;
  1. 在 main.js 中引入并使用自己编写的 router 文件和 VueRouter 插件
import Vue from "vue";
import App from "./App.vue";
import VueRouter from "vue-router";
import router from "./router";

Vue.use(VueRouter);

new Vue({
  render: (h) => h(App),
  router,
}).$mount("#app");
  1. 导航组件用<router-link to="home">首页</router-link>标签包裹,路由组件用<router-view></router-view>标签来展示内容(类似于 slot)

  2. 路由组件传参
    6.1 query 传参(好处:不会影响 router 里面的 path)

    <router-link to="/about/message?id=3"> message </router-link>
    
    mounted() {
     console.log(this.$route); // 通过$route获取传参
    },
    

    6.2 命名路由(作用:路由嵌套层数过多时,简化路由的路径)

    // router/index.js
    const router = new VueRouter({
      routes: [
        {
          path: "/about",
          component: About,
          children: [
            {
              name: "message", // 命名路由
              path: "message", // 路由嵌套时,子级路由中的path不要加斜线( / )
              component: Message,
            },
          ],
        },
      ],
    });
    
     <!-- 当路由跳转的时候,可以直接使用路由的name,不必要写多层 -->
        <router-link :to="{
          name: "message",
          query: { id: 3 },
          }">
           message
         </router-link>
    
        <router-link to="/about/message?id=3"> message </router-link>
    

    6.3 params 传参(注意:使用 params 传参的对象形式时,to 里面的内容必须得写成 name 的形式)

    <router-link to="/about/message/9/杜兰特"> message </router-link>
    
    <router-link
      :to="{
     name:'message',
     params: {
       id:9,
       name:'杜兰特'
     }
    }"
    >
      message
    </router-link>
    
    const router = new VueRouter({
      routes: [
        {
          path: "/home",
          component: Home,
        },
        {
          path: "/about",
          component: About,
          children: [
            {
              name: "message",
              path: "message/:id/:name", // 使用占位符接收params传参
              component: Message,
            },
          ],
        },
      ],
    });
    
    <p>ID : {{$route.params.id}}</p>
    <p>NAME : {{$route.params.name}}</p>
    

    6.4 路由的 props 配置

    const router = new VueRouter({
      routes: [
        {
          path: "/home",
          component: Home,
        },
        {
          path: "/about",
          component: About,
          children: [
            {
              path: "message",
              component: Message,
              // 写法一:对象形式,会以props的形式传给该组件
              // 缺点:数据只能是死数据
              props: {},
    
              // 写法二:布尔形式,会把该组件收到的所有params参数以props形式传给该组件
              // 缺点:只能接收params传参
              props: true,
    
              // 写法三:函数形式,从$route中拿到传参
              props($route) {
                return {
                  id: $route.query.id,
                  title: $route.query.title,
                };
              },
            },
          ],
        },
      ],
    });
    
    export default {
      props: ["id", "title"],
    };
    
    <p>ID : {{id}}</p>
    <p>NAME : {{title}}</p>
    
  3. router-link 的 replace 属性

    • router-link 默认是 push 模式,只需要在 router-link 的标签中增加 :replace="true"属性即可开启 replace 模式
    <router-link to="/about/message" replace> message </router-link>
    
  4. 编程式路由

    <button @click="gotoMessage('7','durant')">消息</button>
    
    methods: {
      gotoMessage(id,title) {
        this.$router.replace("/about/message");
    
        this.$router.push({
         name:'message',
         query:{
           id,
           title
         }
        })
    
        this.$router.push({
          path:'/about/message',
          params:{
            id,
            title
          }
        })
      },
    }
    
    this.$router.back(); // 后退
    this.$router.forward(); // 前进
    this.$router.go(3); // 前进(传正数)后退(传负数)
    
  5. 缓存路由组件

    • 默认情况下,每次切换路由组件,都会重新渲染
    • 可以通过 <keep-alive> 标签包裹需要缓存的组件,只要在<keep-alive>中包裹的组件都会被缓存
    • 缓存组件时,需要指定一个 name 属性(name 对应的值是组件名,指的是 export default { name : Message }),这样就会将指定的组件缓存起来
    <!-- 缓存一个 -->
    <keep-alive include="Message">
      <router-view></router-view>
    </keep-alive>
    
    <!-- 缓存多个 -->
     <keep-alive :include="['Message','News']">
      <router-view></router-view>
     </keep-alive>
    
  6. 新的生命周期(路由组件专属)

    export default {
      activated(){
        // 进入组件时调用
      }
      deactivated(){
        // 离开组件时调用
      }
    }
    
  7. 全局路由守卫

    import VueRouter from "vue-router";
    import Home from "../pages/Home";
    import About from "../pages/About";
    import Message from "../pages/Message";
    
    const router = new VueRouter({
      routes: [
        {
          name: "home",
          path: "/home",
          component: Home,
          meta: { title: "首页" },
        },
        {
          name: "about",
          path: "/about",
          component: About,
          meta: { title: "关于" },
          children: [
            {
              name: "message",
              path: "message",
              component: Message,
              meta: {
                // 配置该组件是否需要权限校验
                isAuth: true,
                title: "消息",
              },
            },
          ],
        },
      ],
    });
    
    router.beforeEach((to, from, next) => {
      // 判断当前路由是否需要登录权限
      if (to.meta.isAuth) {
        // 首先判断该组件是否需要授权
        if (localStorage.getItem("token")) {
          // 再判断是否已经登录过,或者判断是否包含token等信息
          next();
        } else {
          alert("您没有权限查看该页面");
          next("/home");
        }
      } else {
        next();
      }
    });
    
    router.afterEach((to, from) => {
      document.title = to.meta.title || "vue-router";
    });
    
    export default router;
    
  8. 独享路由守卫

    import VueRouter from "vue-router";
    import Home from "../pages/Home";
    import About from "../pages/About";
    import Message from "../pages/Message";
    
    const router = new VueRouter({
      routes: [
        {
          name: "home",
          path: "/home",
          component: Home,
          meta: { title: "首页" },
        },
        {
          name: "about",
          path: "/about",
          component: About,
          meta: { title: "关于" },
          children: [
            {
              name: "message",
              path: "message",
              component: Message,
              meta: {
                isAuth: true,
                title: "消息",
              },
              beforeEnter: (to, from, next) => {
                // 写法与全局前置路由守卫一直
                // 需要注意的是,独享路由守卫只有前置
                console.log(to, from, next);
              },
            },
          ],
        },
      ],
    });
    
    export default router;
    
  9. 组件内路由守卫(一般不用这个)

    export default {
      // 通过路由规则进入该组件时被调用
      beforeRouteEnter(to, from, next) {},
      // 通过路由规则离开该组件时被调用
      beforeRouteLeave(to, from, next) {},
    };
    
  10. history 和 hash 模式的区别

    const router = new VueRouter({
      mode: "history", // 默认是 hash
      routes: [...],
    });
    

    14.1 hash 在 url 中有#,history 没有
    14.2 hash 的兼容性比 history 好
    14.3 history 模式需要后端配合,否则刷新页面后会 404,而 hash 模式不需要

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容

  • 一、Vue2 1.1 模板语法 1.1.1 模板的理解 html 中包含了一些 JS 语法代码,语法分为两种,分别...
    Cola_Mr阅读 487评论 0 1
  • 初识Vue2.0 想让Vue工作,就必须创建一个Vue实例,且要传入一个配置对象 vue容器里的代码依然符合htm...
    Zindex阅读 366评论 0 0
  • 入口文件 vue-2.6.11\src\platforms\web\entry-runtime-with-comp...
    爱吃馒头不吃辣阅读 700评论 0 0
  • vue2 的双向数据绑定是利用ES5 的一个 API[https://so.csdn.net/so/search?...
    Aven丶阅读 275评论 0 0
  • vue特性与其他框架的区别 关于vue vue是一个简洁且轻量化为主要特点的前端MVVM开发框架,vue使用组件化...
    Mr无愧于心阅读 226评论 3 1