一篇文章解锁vue2

本文章对标vue2笔记内容,欢迎补充

文章目录

  • Vue介绍
    • Vue2的生命周期
      • 生命周期钩子
    • 使用vue/cli(脚手架)创建项目工程
    • 组件
    • 属性
      • ref
      • props
      • mixin
      • plugins插件
    • 数组更新检测(会改变原数组)
    • 添加/修改响应式布局
    • vue内置指令
    • 自定义属性directives
    • reduce方法
    • webstorage
      • 方法
      • JSON
    • Null
    • 自定义事件
    • pubsub:消息订阅与发布
      • 安装
      • 导入
      • 使用
    • 全局事件总线
      • 使用
    • 动画与过渡
      • @keyframes属性
      • transition
      • transition-group
    • Promise
      • throw 抛出错误
    • ajax
      • XML
      • http状态码(xhr.status)
      • 返回XMLHttpRequest请求的当前状态(xhr.readyState)
    • 插槽
      • 默认插槽
      • 具名插槽
      • 作用域插槽
        • **slot-scope**属性
    • Vuex
      • state:
      • getter:
      • mutation:
      • actions:
        • 分发 Action
        • 在组件中分发 Action
      • module
        • 命名空间
    • 路由
      • 多级路由
      • 动态路由
      • 路由守卫
        • 路由守卫分类
          • 全局守卫:
          • 独享守卫(当个路由配置中配置):
          • 组件内守卫(组件内利用配置项):
      • 路由的props属性
        • props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
        • props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Demo组件(只能作用于params类型的参数)
        • props值为函数,该函数返回的对象中每一组key-value都会通过props传给Demo组件
      • 路由跳转方法
      • 缓存路由组件
    • 路由器两种工作模式
      • hash模式
      • history模式

Vue介绍

Vue 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用,Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动

Vue2的生命周期

在这里插入图片描述

生命周期钩子

  • beforeCreate: 初始化之前,用于添加一些一开始就要加载的效果,如window.load()

  • created:初始化之后,用于发送一些网络请求来获取数据

  • beforeMount:页面挂载之前,此时的Dom操作已无效

  • mounted:页面挂载之后,用于启动定时器等

  • beforeUpdate:页面更新之前,用于移除事件监听器

  • updated:页面更新之后

  • beforeDestroy:vue实例被销毁前,用于清除定时器以及其他监听事件等,此时操作页面已不会更新

  • destroyed:vue实现销毁后

  • activated:被keep-alive缓存的组件激活时

  • deactivated:被keep-alive缓存的组件停用时

使用vue/cli(脚手架)创建项目工程

使用vue create xxx来创建项目,选择vue版本,可以手动选择需要的配置

在这里插入图片描述

然后npm run serve启动项目

在这里插入图片描述

可以看到项目已经创建完毕,运行版vue.js没有模板解析器,需要使用render函数来获取组件

在这里插入图片描述

render原理相当于

render:function(createElement){return createElement(组件){}
}

组件

vue使用组件化开发来代替多页面的切换,以进行单页面开发,即这些.vue文件

.vue文件有三块基本区域:

template、script、style分别是显示区域、处理事件区域、样式区域,如:

在这里插入图片描述

最后需要使用export default将组件暴露出去,供上级使用如:

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'export default {name: 'HomeView',   // 组件名components: {HelloWorld        // 子组件}
}
</script>

es6三种暴露方法

// 分别(多行)暴露
export function(){}		// 暴露
import {} from '路径'		// 导入
// 统一暴露
function a ; function b ; export {a,b}		// 暴露
import {a,b} from '路径'					// 导入
// 默认暴露
export default function a(){}		// 暴露
import a from '路径'				// 导入

属性

ref

用于获取元素,最早可在mounted钩子使用,如:

<template><div class="home"><img alt="Vue logo" src="../assets/logo.png" ref="imgs" @click="innimg()"><HelloWorld msg="Welcome to Your Vue.js App"/></div>
</template><script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'export default {name: 'HomeView',   // 组件名components: {HelloWorld        // 子组件},methods:{innimg(){this.$refs.imgs.classList.add("bic")}},
}

已成功添加class

在这里插入图片描述

props

用于接收父组件的传参,如:

<template><div class="home"><img alt="Vue logo" src="../assets/logo.png" ref="imgs""><!-- 为子组件传输msg --><HelloWorld msg="Welcome to Your Vue.js App"/></div>
</template><script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'export default {name: 'HomeView',   // 组件名components: {HelloWorld        // 子组件}
}
<template><div class="hello"><!-- 显示msg --><h1>{{ msg }}</h1></div>
</template><!-- 使用props接收父组件的msg -->
<script>
export default {name: 'HelloWorld',props: {msg: String}
}
</script>

若有同名数据冲突:

优先级: props>Methods>Data>Computed>Watch

mixin

将多个组件都需要使用的函数、data等混入,如:

// mixin.js
export default {data: function() {return {mixinData: '来自 Mixin 的数据'};},methods: {mixinMethod: function() {console.log('这是 Mixin 中的方法');}}
};
// 使用混入的数据
<template><div class="about"><h1>This is an about page</h1><h2>{{ mixinData }}</h2></div>
</template><script>
import mixin from '@/mixin/mixin';export default{name: 'AboutView',mixins: [mixin]
}
</script>

plugins插件

包含install方法的一个对象,也可以直接是一个安装函数本身。安装函数会接收到安装它的应用实例和传递给 app.use() 的额外选项作为参数

// 安装一个插件
import { createApp } from 'vue'
const app = createApp({})
app.use(myPlugin, {/* 可选的选项 */
})
// 定义插件
const myPlugin = {install(app, options) {// 配置此应用}
}

数组更新检测(会改变原数组)

  • push() 添加数组元素

  • pop() 删除数组最后一个元素

  • shift() 删除数组第一个元素

  • unshift() 在数组开头添加一个元素

  • splice() array.splice(位置,个数,若有新元素则此函数为增加否则为删除),如果删除一个元素,则返回一个元素的数组。 如果未删除任何元素,则返回空数组

  • sort() 数组排序,默认按字母升序,原理:

var points = [40,100,1,5,25,10];
points.sort(function(a,b){return a-b});	// 升序
points.sort(function(a,b){return b-a});	// 降序
  • reverse() 反转数组顺序

添加/修改响应式布局

对于已经创建的实例,Vue 不允许动态添加根级别的响应式 property。但是,可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式 property。例如,对于:

Vue.set(vm.someObject, 'b', 2)

您还可以使用 vm.$set 实例方法,这也是全局 Vue.set 方法的别名:

this.$set(this.someObject,'b',2)

需要为已有对象赋值多个新 property时:

// 代替Object.assign(this.someObject, { a: 1, b: 2 })
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })

vue内置指令

  • v-on (@):用于添加事件。事件修饰符:

​ stop 阻止事件继续传播冒泡

​ prevent 阻止默认事件

​ once 事件只触发一次

​ capture 使用捕获模式

​ self 只有event.target是当前操作的元素才能触发事件

​ passive 事件默认行为立即执行

注意:在捕获模式中,事件会从外层元素开始向内层元素进行传播,直到达到目标元素。而在冒泡模式中,事件则是从目标元素开始,由内向外进行传播。在Vue.js中,默认情况下事件监听器采用冒泡模式。开发者可以使用.capture修饰符来设置事件监听器使用捕获模式。

  • v-model :双向绑定。修饰符:

​ trim 去掉前后空格

​ number 限制内容为数值类型

​ lazy 失去焦点时再收集内容

  • v-bind : 绑定数据和元素属性(如要添加的类名、a标签的href属性等)

  • v-once: 一次性的插值,数据发送改变时,此处内容不会改变

  • v-html: 将html标签解析(容易被css攻击,不要对用户所输入的内容使用)

  • v-cloak: 当vue开始接管容器时会自带清除这个属性,配合属性选择器来使用

  • v-pre: 让vue不去解析这条语句

  • v-show: 显示与隐藏

自定义属性directives

除了 Vue 内置的一系列指令 (比如 v-modelv-show) 之外,Vue 还允许你注册自定义的指令 (Custom Directives)

一个自定义指令由一个包含类似组件生命周期钩子的对象来定义。钩子函数会接收到指令所绑定元素作为其参数。下面是一个自定义指令的例子,当一个 input 元素被 Vue 插入到 DOM 中后,它会被自动聚焦:

<script setup>
// 在模板中启用 v-focus
const vFocus = {mounted: (el) => el.focus()
}
</script><template><input v-focus />
</template>

reduce方法

reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。

reduce() 可以作为一个高阶函数,用于函数的 compose。

在这里插入图片描述

<button onclick="myFunction()">点我</button><p>数组元素之和: <span id="demo"></span></p><script>
var numbers = [15.5, 2.3, 1.1, 4.7];function getSum(total, num) {return total + Math.round(num);
}
function myFunction(item) {document.getElementById("demo").innerHTML = numbers.reduce(getSum, 0);
}
</script>

webstorage

localstorage 本地存储

sessionstorage 不是持久化的本地存储,是会话级别存储,当页面关闭后就会被销毁

cookie 用于服务器交互,大小受到限制,每次请求一个新的页面时cookie都会被发送过去(浪费宽带),不能跨域使用,需要自己封装set,get

方法

  • webstorage.setItem(‘name’,‘message’) 保存message到name

  • webstorage.getItem(‘name’) 查看name

  • webstorage.removeItem(‘name’) 删除name

  • webstorage.clear() 清空storage

JSON

js对象,用于存储和交换文本信息

  • JSON.parse() 将数据转换为js对象

  • JSON.stringify() 将js对象转换为字符串,服务器端数据一般为字符串

Null

值 null 被写作字面量:null。不像 undefined,null不是全局对象的属性。相反,null是表示缺少的标识,指示变量未指向任何对象。在 API 中,null常在预期的值应是一个对象,但又没有关联的对象的地方使用,undefined是全局对象的一个属性。也就是说,它是全局作用域的一个变量。undefined的最初值就是原始数据类型undefined

自定义事件

使用v-bind绑定自定义事件给子组件实现子传父,利用ref属性获取组件实例来传输自定义事件

使用this. r e f . 自定义事件 . ref.自定义事件. ref.自定义事件.on(自定义方法)

使用this.$emit()触发自定义事件

使用this.$off() 解绑自定义事件,多个事件用数组形式

示例(子组件传父组件):

<template><div><hello-world @myEvent="getC"></hello-world><div>{{ cData }}</div></div>
</template><script>
// 父组件
import HelloWorld from '@/components/HelloWorld.vue';
export default {components: { HelloWorld },name: 'HelloV',data(){return{cData:''}},methods: {getC(c){this.cData = c}}
}
</script>
<template><div class="hello"><button @click="sendFa()">给父组件</button></div>
</template><script>
// 子组件
export default {name: 'HelloWorld',props: {msg: String},methods:{sendFa(){const c = 'cData'this.$emit('myEvent',c)}}
}
</script>

pubsub:消息订阅与发布

适用于组件间通信

安装

npm i pubsub-js

导入

import pubsub from ‘pubsub-js’

使用

订阅消息/接收数据,一般在mounted钩子中使用

this.pubid = pubsub.subscribe(‘自定义方法’,回调函数)

发布消息/提供数据

pubsub.publish(‘自定义方法’,数据)

示例(子组件传父组件):

<template><div class="hello"><h1>{{ msg }}</h1><p><button @click="sendFa()">给父组件</button></p></div>
</template><script>
import PubSub from 'pubsub-js';
export default {name: 'HelloWorld',props: {msg: String},methods:{sendFa(){// 发送消息 const c = 'cData'// this.$emit('myEvent',c)PubSub.publish('hello',c)}}
}
</script>
<template><div><hello-world @myEvent="getC"></hello-world><div>{{ cData }}</div></div>
</template><script>
import PubSub from 'pubsub-js';
import HelloWorld from '@/components/HelloWorld.vue';
export default {components: { HelloWorld },name: 'HelloV',data(){return{cData:''}},methods: {getC(){}},mounted(){// 接收消息 const _this = thisPubSub.subscribe('hello',(msg,c)=>{_this.cData = cconsole.log(msg);console.log(c);})}
}
</script>

全局事件总线

GlobalEventBus:让所有组件可相互通信

使用vc或vm作为中转,在beforeCreate钩子内创建,一般以$bus命名

依赖于一个重要的内置关系:

VueComponent.prototype.__ proto__ ===Vue.prototype

让组件实例对象可以访问到vue原型上的属性方法

使用

首先挂载到main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'Vue.config.productionTip = falsenew Vue({router,store,render: h => h(App),beforeCreate(){Vue.prototype.$bus = this}
}).$mount('#app')

父组件监听自定义事件

<template><div><hello-world @myEvent="getC"></hello-world><div>{{ cData }}</div></div>
</template><script>
import HelloWorld from '@/components/HelloWorld.vue';
export default {components: { HelloWorld },name: 'HelloV',data(){return{cData:''}},methods: {getC(){}},mounted(){this.$bus.$on('myEvent',(data)=>{this.cData = data})},// 用完就解绑自定义事件beforeDestroy(){this.$bus.$off('myEvent')}
}
</script>

子组件通过自定义事件发送数据

<template><div class="hello"><h1>{{ msg }}</h1><button @click="sendFa()">给父组件</button></div>
</template>
<!-- 使用props接收父组件的msg -->
<script>
export default {name: 'HelloWorld',props: {msg: String},methods:{sendFa(){const c = 'cData'this.$bus.$emit('myEvent',c)}}
}
</script>

动画与过渡

@keyframes属性

from 开始时, to 结束时

<template><div><div class="ani"></div></div>
</template><style scoped>
.ani{margin-left: 40%;background: black;width: 200px;height: 200px;animation: anime 5s infinite;
}
@keyframes anime{from{rotate: 0;}to{rotate: 180deg;}
}
</style>

transition

是一个内置组件,这意味着它在任意别的组件中都可以被使用,无需注册。它可以将进入和离开动画应用到通过默认插槽传递给它的元素或组件上。进入或离开可以由以下的条件之一触发:

  • 由 v-if 所触发的切换

  • 由 v-show 所触发的切换

  • 由特殊元素 切换的动态组件

  • 改变特殊的 key 属性

例如:

<template><div><hello-world @myEvent="getC"></hello-world><div>{{ cData }}</div><transition><div class="ani" v-if="show"></div></transition><button @click="show = !show">000</button></div>
</template><script>
import HelloWorld from '@/components/HelloWorld.vue';
export default {components: { HelloWorld },name: 'HelloV',data(){return{cData:'',show: false}},}
</script><style scoped>
.ani{width: 200px;height: 200px;margin-left: 40%;background-color: black;
}
.v-enter-active,
.v-leave-active {transition: opacity 0.5s ease;
}.v-enter-from,
.v-leave-to {opacity: 0;
}
</style>
  • .v-enter-active 整个进入的过程

  • .v-enter 进入时

  • .v-leave-active 整个离开的过程

  • .v-leave 离开时

  • .v-enter-to 进入的终点

  • .v-leave-to 离开的终点

想要先执行离开动画,然后在其完成之后再执行元素的进入动画,可以加入mode如下:

<Transition mode="out-in">...
</Transition>

transition-group

支持和 基本相同的 props、CSS 过渡 class 和 JavaScript 钩子监听器,但有以下几点区别:

  • 默认情况下,它不会渲染一个容器元素。但你可以通过传入 tag prop 来指定一个元素作为容器元素来渲染。
  • 过渡模式在这里不可用,因为我们不再是在互斥的元素之间进行切换。
  • 列表中的每个元素都必须有一个独一无二的 key attribute。
  • CSS 过渡 class 会被应用在列表内的元素上,而不是容器元素上。
<template><div><hello-world @myEvent="getC"></hello-world><div>{{ cData }}</div><transition><div class="ani" v-if="show"></div></transition><button @click="show = !show">000</button><TransitionGroup name="list" tag="ul" style="margin-left: 30%;"><li v-for="item in items" :key="item">{{ item }}</li></TransitionGroup><button @click="items--">000</button></div>
</template><script>
import HelloWorld from '@/components/HelloWorld.vue';
export default {components: { HelloWorld },name: 'HelloV',data(){return{cData:'',show: false,items: 6}},methods: {getC(){}},
}
</script><style scoped>
.ani{width: 200px;height: 200px;margin-left: 40%;background-color: black;
}
.list-enter-active,
.list-leave-active {transition: all 0.5s ease;
}
.list-enter-from,
.list-leave-to {opacity: 0;transform: translateX(30px);
}
</style>

Promise

js中进行异步编程的新解决方案

promise是一个构造函数,promise对象用来封装一个异步操作并获取其成功/失败的结果值,异步方法不会立即返回最终值,而是返回一个 promise,以便在将来的某个时间点提供该值

一个 Promise 必然处于以下几种状态之一:

  • 待定(pending):初始状态,既没有被兑现,也没有被拒绝。
  • 已兑现(fulfilled):意味着操作成功完成。
  • 已拒绝(rejected):意味着操作失败

可以使用async来创建一个异步函数,示例如下:

<script>
export default {name: 'HelloV',data(){return{ob1: {io: 1,vc: '255'}}},methods: {// 创建异步方法async getOb(){return this.ob1},// 获取异步方法返回的promise对象,使用then方法获得promise中的对象,并使用解构赋值提取其中一个元素getOb1(){this.getOb().then((value)=>{const {io} = valueconsole.log(io)})}}
}
</script>

.then方法:用于调用resolve和reject方法,返回一个promise对象,例如:

<script>
export default {name: 'HelloV',methods: {getProm(){const pro = new Promise((resolve)=>{// resolve 调用视为成功,改变此Promise状态为已成功resolve('27')}).then((value)=>{// 使用.then方法获取resolve方法的值,并返回一个Promise对象console.log(value,pro);})}},
}
</script>

在这里插入图片描述

可以看到Promise状态变为fulfilled

再来看看reject方法

<script>
export default {name: 'HelloV',methods: {getProm(){const pro = new Promise((resolve,reject)=>{reject('20')}).then((reason)=>{console.log(reason,pro);}).catch((e)=>{console.log(e);})}},
}
</script>

以上内容解释:

首先创建一个Promise对象,Promise构造函数有两个参数:resolverejectresolve用于将Promise的状态标记为已成功,并传递一个成功值;reject用于将Promise的状态标记为已失败,并传递一个失败原因,这里使用的是reject方法,所以会使Promise的状态变为已失败,并传递’20’作为失败原因,.catch函数用于捕获Promise失败的函数,如果此时不捕获错误则会报错,.catch函数的参数为失败原因,由于Promise失败了,.then函数不会执行,.catch捕获到错误原因控制台输出’20’

在这里插入图片描述

throw 抛出错误

这里没有使用catch捕获,直接throw抛出错误

<script>
export default {name: 'HelloV',methods: {getProm(){const pro = new Promise((resolve,)=>{// resolve 调用视为成功,改变此Promise状态为已成功resolve('20')}).then((value)=>{throw value})console.log(pro)}}
}
</script>

效果如下:

在这里插入图片描述

ajax

向服务器发送异步请求,无需刷新获取数据

XML

可扩展标记语言,用于传输与存储数据,与html不同,没有预定义标签,全是自定义标签,现已经被JSON取代

核心对象XMLHttpRequest

使用步骤:

<script>
export default {name: 'HelloV',methods: {getXML(){// 创建核心对象const xhr = new XMLHttpRequest()// 设置请求信息xhr.open("GET","/js/test.JSON",true)// 发送请求xhr.send(0)// 进行判断输出xhr.onreadystatechange = ()=>{if(xhr.readyState !== 4)  returnif(xhr.status >= 200 && xhr.status < 300){console.log(xhr.responseText);}}}}

已经成功显示

在这里插入图片描述

http状态码(xhr.status)

1xx: 信息正在处理

2xx: 请求成功

3xx: 附加操作(重定向)

​ 301: 永久重定向

​ 302: 临时重定向

4xx: 无法处理(客户端错误)

​ 400: 语法错误

​ 401: 未认证

​ 403: 禁止访问

​ 404: 资源未找到

5xx: 服务器错误

​ 500: 服务器故障

​ 503: 服务器繁忙

返回XMLHttpRequest请求的当前状态(xhr.readyState)

0: 未初始化(未调用open方法)

1: 启动(已调用open方法,未调用send方法)

2: 发送(已调用send方法,未接收到响应)

3: 接收(已接收到部分响应数据)

4: 完成(已接收到所有响应数据)

插槽

父元素传入的内容会显示在子组件的插槽处

默认插槽

在组件标签内传入元素,使用slot标签作为插槽,内容为默认值,有传入元素时会被替代

// 父组件
<template><div><hello-world @myEvent="getC">hello</hello-world></div>
</template>
// 子组件
<template><div class="hello"><h1>{{ msg }}</h1><p><!-- 父组件没有传入数据时默认显示slot --><slot>slot</slot></p></div>
</template>

具名插槽

有多个插槽时,使用name属性命名,传入内容时使用slot=“”(新写法v-slot:)来指定插入的插槽

// 父组件,注意写法
<template><div><hello-world @myEvent="getC"><template v-slot:div>hello</template></hello-world></div>
</template>
// 子组件
<template><div class="hello"><p><button @click="sendFa()">给父组件</button><slot name="p"></slot></p><div><slot name="div"></slot></div></div>
</template>

作用域插槽

适用于data内容在子组件中时,可以像对组件传递 props 那样,向一个插槽的出口上传递 attributes

// 父组件
<template><div><hello-world @myEvent="getC"><template scope="data">{{ data.nm }}</template></hello-world></div>
</template>
// 子组件
<template><div class="hello"><p><button @click="sendFa()">给父组件</button></p><div>插槽<slot :nm="nm"></slot></div></div>
</template><script>
export default {name: 'HelloWorld',data(){return{nm: ['mis','sd','op']}}
}
</script>
slot-scope属性

利用slot-scope="scope"的scope可以取出父元素所绑定的数据,例如 element-ui 中的 table 组件,在渲染表格行时我们经常需要用到 slot-scope 来获取当前行的数据

<template><el-table :data="tableData"><el-table-column label="序号"><template slot-scope="scope"><span>{{ scope.$index + 1 }}</span></template></el-table-column><el-table-column label="姓名"><template slot-scope="scope"><span>{{ scope.row.name }}</span></template></el-table-column><el-table-column label="年龄"><!-- 支持直接通过 {} 去解构数据 --><template slot-scope="{row}"><span>{{ row.age }}</span></template></el-table-column></el-table>
</template>

Vuex

实现多组件共享数据,每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。每个应用将仅仅包含一个 store 实例。

以下是vuex基本原理图

在这里插入图片描述

以下根据vux(store)包含内容一一介绍

state:

存储需要共享的数据

getter:

用于加工state中的属性,有时候我们需要从 store 中的 state 中派生出一些状态,例如对列表进行过滤并计数,如果有多个组件需要用到此属性,Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)

从 Vue 3.0 开始,getter 的结果不再像计算属性一样会被缓存起来

const store = createStore({state: {todos: [{ id: 1, text: '...', done: true },{ id: 2, text: '...', done: false }]},getters: {doneTodos (state) {return state.todos.filter(todo => todo.done)}}
})

mutation:

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

const store = createStore({state: {count: 1},mutations: {increment (state) {// 变更状态state.count++}}
})

不过你不能直接调用一个 mutation 处理函数。这个选项更像是事件注册:“当触发一个类型为 increment 的 mutation 时,调用此函数。”要唤醒一个 mutation 处理函数,你需要以相应的 type 调用 store.commit 方法:

store.commit('increment')

actions:

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

让我们来注册一个简单的 action:

const store = createStore({state: {count: 0},mutations: {increment (state) {state.count++}},actions: {increment (context) {context.commit('increment')}}
})

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,实践中,我们会经常用到 ES2015 的参数解构来简化代码

actions: {increment ({ commit }) {commit('increment')}
}
分发 Action

Action 通过 store.dispatch 方法触发:

store.dispatch('increment')

由于mutation 必须同步执行这个限制,Action 不受约束,我们可以在 action 内部执行异步操作:

actions: {incrementAsync ({ commit }) {setTimeout(() => {commit('increment')}, 1000)}
}
在组件中分发 Action

你在组件中使用 this.$store.dispatch('xxx') 分发 action,或者使用 mapActions 辅助函数将组件的 methods 映射为 store.dispatch 调用(需要先在根节点注入 store):

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')`})}
}

module

当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:

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

对于模块内部的 getter,根节点状态会作为第三个参数暴露出来:

const moduleA = {// ...getters: {sumWithRootCount (state, getters, rootState) {return state.count + rootState.count}}
}
命名空间

默认情况下,模块内部的 action 和 mutation 仍然是注册在全局命名空间的——这样使得多个模块能够对同一个 action 或 mutation 作出响应。Getter 同样也默认注册在全局命名空间,必须注意,不要在不同的、无命名空间的模块中定义两个相同的 getter 从而导致错误。

如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。例如:

const store = createStore({modules: {account: {namespaced: true,// 模块内容(module assets)state: () => ({ ... }), // 模块内的状态已经是嵌套的了,使用 `namespaced` 属性不会对其产生影响getters: {isAdmin () { ... } // -> getters['account/isAdmin']},actions: {login () { ... } // -> dispatch('account/login')},mutations: {login () { ... } // -> commit('account/login')},// 嵌套模块modules: {// 继承父模块的命名空间myPage: {state: () => ({ ... }),getters: {profile () { ... } // -> getters['account/profile']}},// 进一步嵌套命名空间posts: {namespaced: true,state: () => ({ ... }),getters: {popular () { ... } // -> getters['account/posts/popular']}}}}}
})

启用了命名空间的 getter 和 action 会收到局部化的 getterdispatchcommit。换言之,你在使用模块内容(module assets)时不需要在同一模块内额外添加空间名前缀。更改 namespaced 属性后不需要修改模块内的代码

路由

基于vue-router插件,vue2只能使用3版本及以下

使用router-link标签的to属性实现跳转

普通配置如下:

import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'Vue.use(VueRouter)const routes = [{path: '/',name: 'home',component: HomeView}{path: '/about',name: 'about',component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')}
]const router = new VueRouter({routes
})export default router

根据所配置的路由跳转,所跳转的路由的组件内容就会显示在router-view标签处,而router-link标签则是通过to属性选择路由,点击这个标签进行路由跳转

<template><div id="app"><nav><router-link to="/">Home</router-link> |<router-link to="/about">About</router-link></nav><router-view/></div>
</template>

多级路由

有路由嵌套是,可以使用路由中children属性配置子路由

const router = new VueRouter({routes: [{path: '/user/:id',component: User,children: [{// 当 /user/:id/profile 匹配成功,// UserProfile 会被渲染在 User 的 <router-view> 中path: 'profile',component: UserProfile},{// 当 /user/:id/posts 匹配成功// UserPosts 会被渲染在 User 的 <router-view> 中path: 'posts',component: UserPosts}]}]
})

动态路由

我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使用“动态路径参数”(dynamic segment) 来达到这个效果:

const User = {template: '<div>User</div>'
}const router = new VueRouter({routes: [// 动态路径参数 以冒号开头{ path: '/user/:id', component: User }]
})

在配置component的时候,需要动态导入组件,有两种导入方式,import和require方式

  • import属于es6导入方式,只支持静态导入,也就是说,你不能够使用变量或表达式,只能使用字符串。

  • require属于commonJS方式,可以支持动态的导入,但笔者尝试中,可以使用``模板字符串方式,貌似也无法直接使用变量。这里尽量用字符串拼接,而不是用变量去代替拼接的字符串

// 字符串拼接方式
component: import('@/view'+'/sys/user')
// 模板字符串方式,webpack4+版本需使用require方式,注意,`@${item.curl}`,是不行的!必须指定一个目录,不能全用变量代替
component: (resolve) => require([`@/view${item.curl}`], resolve),

路由守卫

对路由跳转添加限制,有to,from,next()三个参数,以前置路由守卫为例:

router.beforeEach((to,from,next)=>{// to为要跳转的路由(目标),from为开始跳转的路由(起始),next()为允许路由跳转(放行)if(to.name === "login"){next();}}

以下为限制在没有登陆时对用户路由跳转的限制:

import Vue from 'vue'
import VueRouter from 'vue-router'
import Login from '../views/Login.vue'
import MainBox from '@/views/MainBox.vue'
import RoutesConfig from './config'
import store from '@/store/index'Vue.use(VueRouter)const routes = [{path: "/login",name: "login",component: Login},{path: "/mainbox",name: "mainbox",component: MainBox// 嵌套路由根据权限动态添加},]const router = new VueRouter({routes
})// 路由拦截(路由守卫),路由跳转之前
router.beforeEach((to,from,next)=>{if(to.name === "login"){next();}else{// 是否登陆if(!localStorage.getItem("token")){next({path: "login"})}else{if(!store.state.isGetFullRoute){// 重新加载所有路由,token刚添加路由还没加载完毕next({path: to.fullPath})AddRoutesConfig()}else{// 加载一遍后就不用再加载所有路由了,避免死循环next()}}}
})const AddRoutesConfig = ()=>{RoutesConfig.forEach(item=>{router.addRoute("mainbox",item)})// 改变isGetFullRoute,代表路由已加载完毕store.commit("changeGetFullRoute",true);
}export default router
路由守卫分类
全局守卫:

前置路由守卫 beforeEach(to,from,next){}

后置路由守卫 afterEach(to,from){}

独享守卫(当个路由配置中配置):

beforeEnter(to,from,nect){}

组件内守卫(组件内利用配置项):

通过路由规则进入前 beforeRouteEnter(to,from,next){}

通过路由规则离开前 beforeRouteLeave(to,form,next){}

路由的props属性

props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
children: [{name: 'demo',path:'demo',component: Demo,// props对象中所有的key-value的组合最终都会通过props传给Demo组件props:{id: '1',title: 'hello'}}
]

在Demo组件中使用props接收传递来的数据

<template><div><ul><li>接收的id为{{id}}</li><li>接收的title为{{title}}</li></ul></div>
</template><script>
export default {name: 'Demo',// 接收组件传递来的数据props: ['id', 'title']
}
</script>
props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Demo组件(只能作用于params类型的参数)
{name: 'demo',path:'demo/:id/:title', //使用占位符声明接收params参数component: Demo,// 第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件props: true
}

传递params参数

<li v-for="item in list" :key="item.id"><router-link :to="{name: 'demo',params: {id: item.id,title: item.title}}">{{ item.title }}</router-link>
</li>

Demo组件接收参数

<template><div><ul><li>接收的id为{{id}}</li><li>接收的title为{{title}}</li></ul></div>
</template><script>
export default {name: 'Demo',// 接收组件传递来的数据props: ['id', 'title']
}
</script>
props值为函数,该函数返回的对象中每一组key-value都会通过props传给Demo组件
{name: 'demo',path:'demo/:id/:title', //使用占位符声明接收params参数component: Demo,// 第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件// props函数会自动调用并提供一个$route参数 可以通过$route来获取想要的数据传递给组件props($route) {return {id: $route.params.id,title: $route.params.title,// 还可以返回一些别的数据a: 1,b: "hello"}}
}

Demo组件使用props接收参数

<template><div><ul><li>接收的id为{{id}}</li><li>接收的title为{{title}}</li>{{a}}-----{{b}}</ul></div>
</template><script>
export default {name: 'Demo',// 接收组件传递的参数props: ['id', 'title', 'a', 'b']
}
</script>

路由跳转方法

this.$router.push({path/name:‘’,query/param:{}}) 带参数根据路径或路由名跳转

this.$router.replace() 与上面push用法一致

this.$router.forward() 路由前进一级

this.$router.back() 路由后退一级

this.$router.go() 路由前进(n)或后退(-n) n级

缓存路由组件

使组件保持挂载,被切换时不被销毁

<!-- 非活跃的组件将会被缓存! -->
<KeepAlive><component :is="activeComponent" />
</KeepAlive>

<KeepAlive> 默认会缓存内部的所有组件实例,但我们可以通过 include 来定制该行为

<!-- 以英文逗号分隔的字符串 -->
<KeepAlive include="a,b"><component :is="view" />
</KeepAlive><!-- 正则表达式 (需使用 `v-bind`) -->
<KeepAlive :include="/a|b/"><component :is="view" />
</KeepAlive><!-- 数组 (需使用 `v-bind`) -->
<KeepAlive :include="['a', 'b']"><component :is="view" />
</KeepAlive>

路由器两种工作模式

hash模式

如:https://element.eleme.cn/#/zh-CN/component/installation

在url中#后的内容为hash值,hash值不会包含在http请求中(带给服务器),兼容性较好

history模式

如:https://cn.vuejs.org/guide/introduction.html

会将所有url内容带给服务器,会造成404,需要进行过滤配置

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/45079.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

可道云teamOS,用个人标签和公共标签,文件分类更多样

在信息爆炸的时代&#xff0c;我们每天都在与海量的数据和信息打交道。如何在这些纷繁复杂的信息中快速找到我们需要的&#xff0c;成为了摆在我们面前的一大难题。 为大家介绍一下可道云teamOS个人标签和公共标签功能&#xff0c;让信息的整理与搜索变得简单高效。 一、个人…

MySQL 面试相关问题

写在前面&#xff1a; 不喜勿喷&#xff0c;暴躁作者又不求你给钱【没办法&#xff0c;遇见的狗喷子太多了&#x1f436;】欢迎大家在评论区留言&#xff0c;指正文章中的信息错误有一些其他相关的问题&#xff0c;可以直接评论区留言&#xff0c;作者看到会及时更新到文章末尾…

【thingsbord源码编译】 显示node内存不足

编译thingsbord显示报错 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory问题原因分析 重新安装java版本 编译通过

基于React 实现井字棋

一、简介 这篇文章会基于React 实现井字棋小游戏功能。 二、效果演示 三、技术实现 import {useEffect, useState} from "react";export default (props) > {return <Board/> }const Board () > {let initialState [[, , ], [, , ], [, , ]];const [s…

yolov8、RTDETR无法使用多个GPU训练

yolov8、RTDETR无法使用多个GPU训练 网上看了好多解决方法&#xff1a; 什么命令行 CUDA_VISIBLE_DEVICES0,1 python train.py 环境变量都不行 最后找到解决方案&#xff1a;在ultralytics/engine/trainer.py 中的第246行 将 self.model DDP(self.model, device_ids[RANK])…

OWASP ZAP

OWASP ZAP简介 开放式Web应用程序安全项目&#xff08;OWASP&#xff0c;Open Web Application Security Project&#xff09;是一个组织&#xff0c;它提供有关计算机和互联网应用程序的公正、实际、有成本效益的信息。ZAP则是OWASP里的工具类项目&#xff0c;也是旗舰项目&a…

VBA 批量发送邮件

1. 布局 2. 代码 前期绑定的话&#xff0c;需要勾选 Microsoft Outlook 16.0 Object Library Option ExplicitConst SEND_Y As String "Yes" Const SEND_N As String "No" Const SEND_SELECT_ALL As String "Select All" Const SEND_CANCEL…

Vue从零到实战第一天

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…

【PostgreSQL】Spring boot + Mybatis-plus + PostgreSQL 处理json类型情况

Spring boot Mybatis-plus PostgreSQL 处理json类型情况 一、前言二、技术栈三、背景分析四、方案分析4.1 在PostgreSQL 数据库中直接存储 json 对象4.2 在PostgreSQL 数据库中存储 json 字符串 五、自定义类型处理器5.1 定义类型处理器5.2 使用自定义类型处理器 一、前言 在…

SpringCloud--Eureka集群

Eureka注册中心集群 为什么要集群 如果只有一个注册中心服务器&#xff0c;会存在单点故障&#xff0c;不可以高并发处理所以要集群。 如何集群 准备三个EurekaServer 相互注册&#xff0c;也就是说每个EurekaServer都需要向所有的EureakServer注册&#xff0c;包括自己 &a…

漏洞扫描器之XRAY的安装及破解

XRAY简介 xray 是一款功能强大的安全评估工具&#xff0c;由多名经验丰富的一线安全从业者呕心打造而成&#xff0c;主要特性有&#xff1a; 检测速度快&#xff1a;发包速度快 ; 漏洞检测算法高效。 支持范围广&#xff1a;大至 OWASP Top 10 通用漏洞检测&#xff0c;小至…

接口测试框架基于模板自动生成测试用例!

引言 在接口自动化测试中&#xff0c;生成高质量、易维护的测试用例是一个重要挑战。基于模板自动生成测试用例&#xff0c;可以有效减少手工编写测试用例的工作量&#xff0c;提高测试的效率和准确性。 自动生成测试用例的原理 为了实现测试用例数据和测试用例代码的解耦&a…

[激光原理与应用-109]:南京科耐激光-激光焊接-焊中检测-智能制程监测系统IPM介绍 - 12 - 焊接工艺之影响焊接效果的因素

目录 一、影响激光焊接效果的因素 1.1、光束特征 1.2、焊接特征 1.3、保护气体 二、材料对焊接的影响 2.1 材料特征 2.2 不同材料对激光的吸收率 &#xff08;一&#xff09;、不同金属材料对不同激光的吸收率 1. 金属材料对激光的普遍反应 2. 不同波长激光的吸收率差…

React Hooks学习笔记

一、usestate的使用方法-初始化state函数 import React, { useState } from "react"; function App() {const [count, setCount] useState(0);return (<div><p>点击{count}次</p><button onClick{() > setCount(count 1)}>点击</bu…

为何现在大屏的UI设计和前端开发项目已经多到咱们快忙不过来了?

**为何现在大屏的UI设计和前端开发项目已经多到咱们快忙不过来了&#xff1f;** **一、引言** 随着科技的进步和消费者需求的不断升级&#xff0c;大屏设备&#xff08;如智能电视、车载屏幕、拼接屏等&#xff09;在各行各业中的应用越来越广泛。这导致了大屏UI设计和前端开…

四步教你实现一个前端的动态实时时间(可自定义时间格式)

前言&#xff1a;我是在Vue中做的 1、将你的实时时间放在一个合适的位置 <div style"position: relative; padding-top: 0px; margin-top: -5px"><div style"position: absolute; left: auto; color: black; background-color: #7fd584; font-size: 3…

欧科云链研究院:坎昆升级后,Layer2变得更好了吗?

本文由欧科云链研究院OKG Research联合PANews出品&#xff1a;以数据为导向&#xff0c;洞察真实的链上世界。 作者&#xff5c;Jason Jiang, OKG Research 坎昆升级后&#xff0c;以太坊L2的交易费用降低明显且吞吐量有所提升&#xff0c;但整体生态并没有迎来想象中的繁荣景…

教你怎么不开DLSS3.0也能有效提高永劫无间帧数

永劫无间&#xff0c;一款国风的多人对战竞技游戏&#xff0c;游戏画面特别精美&#xff0c;在游戏中给玩家强烈的打击感&#xff0c;玩家在游玩过程中仿佛置身于游戏&#xff0c;而且此游戏非常受玩家欢迎。游戏中可以进行三人、双人、单人进行游玩&#xff0c;我们需要选择出…

Numpy常用的30个经典操作以及代码演示

目录 以下是具体的操作步骤和示例代码&#xff1a; 数组创建 数组操作 数组计算 统计分析 矩阵操作 这些操作涵盖了数组创建、数组操作、数组计算、统计分析和矩阵操作等多个方面. 以下是具体的操作步骤和示例代码&#xff1a; 首先导入Numpy import numpy as np数组…

sublime中无法找到Package Control或Install Package

在Crtl Shift P 中无法查找到Package Control或Install Package或调用产生报错。 可以尝试在 首选项 ---- > 设置中 检查配置文件"ignored_packages":紧跟的中括号中是否为空&#xff0c;如果不为空请删除其中内容。 如果不确定内容&#xff0c;可以用下面的…