本文主要是介绍Vue - 5( 11000 字 Vue2 入门级教程),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一:Vue 初阶
1.1 组件自定义事件
在 Vue 中,组件间通过自定义事件进行通信是一种常见的模式。自定义事件允许子组件向父组件发送消息,也可以在组件内部进行事件的绑定、触发和解绑。让我们详细讲解这些知识点。
1.1.1 组件自定义事件
在 Vue 中,自定义事件是指子组件通过 $emit
方法触发,父组件通过 v-on
监听并响应的一种事件机制,一种组件间通信的方式,适用于:子组件 ===> 父组件
1.1.1.1触发自定义事件
在子组件中,使用 $emit
方法来触发自定义事件。例如,Student 组件中的 sendStudentlName
方法通过 $emit
触发了一个名为 atguigu
的自定义事件,并传递了一些参数。
sendStudentlName(){this.$emit('atguigu', this.name, 666, 888, 900)
}
1.1.1.2. 监听自定义事件
在父组件中,通过 v-on
或简写 @
来监听子组件触发的自定义事件。例如,假设 App 父组件包含了一个 <Student>
子组件,并监听了子组的 atguigu
事件。
<template><div><Student @atguigu="handleAtguiguEvent" />//触发了名为 "atguigu" 的自定义事件时,父组件将调用名为 "handleAtguiguEvent" 的方法来处理该事件。</div>
</template<script>
export default {methods: {handleAtguiguEvent(name, num1, num2, num3) {console.log('Received event from Student component:', name, num1, num2, num3);}}
}
</script>
组件上也可以绑定原生DOM事件,需要使用native
修饰符
1.1.1.3. 解绑自定义事件
Vue 提供了 $off
方法用于解绑自定义事件。
-
解绑特定的事件
在子组件中可以使用
this.$off('event-name')
解绑特定的事件。unbind(){this.$off('atguigu'); // 解绑单个事件 }
-
解绑多个事件
可以同时解绑多个事件。
unbind(){this.$off(['atguigu', 'demo']); // 解绑多个事件 }
-
解绑所有事件
如果不传入参数,则会解绑所有自定义事件。
unbind(){this.$off(); // 解绑所有的自定义事件 }
1.1.2 组件销毁与事件失效
Vue 组件销毁时,其所有自定义事件也会失效。在 Student
组件中,使用 this.$destroy()
方法可以销毁当前组件实例,这将导致该组件的所有自定义事件失效,即无法再触发和响应。
death(){this.$destroy(); // 销毁当前Student组件的实例,销毁后所有自定义事件失效。
}
完整代码示例
下面是整合了这些知识点的完整示例:
<template><div><Student @atguigu="handleAtguiguEvent" /><School :getSchoolName="handleSchoolName" /></div>
</template><script>
import Student from './Student.vue';
import School from './School.vue';export default {components: {Student,School},methods: {handleAtguiguEvent(name, num1, num2, num3) {console.log('Received event from Student component:', name, num1, num2, num3);},handleSchoolName(schoolName) {console.log('Received school name from School component:', schoolName);}}
}
</script>
在这个示例中,<App>
父组件中引入了 <Student>
和 <School>
子组件,分别监听了它们触发的自定义事件。当子组件触发对应的事件时,父组件中的方法会被调用,实现了组件间的通信。
1.2 全局事件总线
全局事件总线是 一种组件间通信的方式,适用于任意组件间通信
在Vue中,事件总线是一种通信机制,允许不同组件之间进行通信。Vue实例提供了一个事件系统,可以通过$on
方法监听事件,通过$emit
方法触发事件,通过$off
方法解绑事件监听器。
首先,在Vue实例上创建一个事件总线:
const bus = new Vue();// 将事件总线挂载到Vue原型上,这样所有组件都可以访问到它
Vue.prototype.$bus = bus;
然后,在任何组件中,你可以通过$bus.$on
来监听事件,通过$bus.$emit
来触发事件:
// 在组件A中监听事件
this.$bus.$on('my-event', (data) => {console.log('Received data:', data);
});// 在组件B中触发事件
this.$bus.$emit('my-event', { message: 'Hello world!' });
在以上示例中,组件A监听了my-event
事件,组件B触发了my-event
事件,并传递了一个包含消息的对象。当事件被触发时,组件A中的回调函数会被调用,打印出接收到的数据。
要解绑事件监听器,可以使用$off
方法。在组件销毁或不需要监听事件时,最好手动解绑事件,以避免内存泄漏。
// 在组件销毁时解绑事件监听器
beforeDestroy() {this.$bus.$off('my-event');
}
通过以上方式,你可以在Vue中实现事件总线的功能,并且可以确保在不需要时正确地解绑事件监听器。
1.3 消息订阅与发布
消息订阅与发布(Publish/Subscribe,Pub/Sub)是一种常用的软件架构模式,用于组件间通信
在消息订阅与发布模式中,有以下几个重要的角色和概念:
- 发布者(Publisher):负责发送消息。
- 订阅者(Subscriber):接收和处理特定类型的消息。
- 主题(Topic):用于定义消息的类型或名称,订阅者可以根据主题进行订阅。
- 消息(Message):发布者发送的数据或事件。
1.3.1 详细步骤
-
安装 pubsub-js
首先,通过
npm i pubsub-js
安装 PubSub.js,这是一个常用的 JavaScript 发布/订阅库。 -
引入并使用
在需要使用的文件中,通过
import pubsub from 'pubsub-js'
导入 PubSub.js。 -
消息订阅
订阅者(例如组件 A)可以通过
pubsub.subscribe('topicName', callback)
来订阅特定的主题(topic)。当发布者发布与该主题相关的消息时,订阅者的回调函数(callback)将被调用并接收到消息。示例代码:
methods: {demo(data) {// 处理接收到的数据console.log('Received data:', data);} }, mounted() {// 订阅主题 'xxx',并指定回调函数为 this.demothis.pid = pubsub.subscribe('xxx', this.demo); }
-
消息发布
发布者可以通过
pubsub.publish('topicName', data)
来发布特定主题的消息,并将数据(data)传递给所有订阅了该主题的订阅者。示例代码:
// 在某处发布名为 'xxx' 的主题,并发送数据 pubsub.publish('xxx', { message: 'Hello!' });
-
取消订阅
为了避免内存泄漏或意外的消息处理,建议在组件销毁前取消订阅。通过
pubsub.unsubscribe(pid)
取消之前设置的订阅。示例代码:
beforeDestroy() {// 在组件销毁前取消订阅pubsub.unsubscribe(this.pid); }
示例解释
以上示例展示了如何在 Vue.js 组件中使用 PubSub.js 实现消息订阅与发布:
- 当组件 A 的
mounted
钩子函数执行时,它订阅了名为 ‘xxx’ 的主题,并指定了this.demo
作为回调函数。 - 在其他任何地方(可能是另一个组件或模块),通过
pubsub.publish('xxx', data)
发布 ‘xxx’ 主题的消息,并传递数据data
。 - 一旦消息发布,订阅者(即组件 A)的
demo
方法将被调用,接收并处理消息中的数据。 - 在组件 A 销毁之前,通过
beforeDestroy
钩子取消订阅,以确保在组件销毁后不再接收或处理来自该主题的消息。
这种模式的优势在于,它使不同模块之间的通信更加松散耦合,模块间不直接依赖于彼此,而是通过订阅和发布消息进行通信,从而提高了系统的可扩展性和灵活性。
1.4 nextTick
在 Vue.js 中,this.$nextTick
是一个异步方法,它接收一个回调函数作为参数。它的作用是在下一次 DOM 更新周期结束后执行指定的回调函数。
通常情况下,Vue 在更新 DOM 时是异步执行的,也就是说当你修改了数据后,Vue 并不会立即更新 DOM,而是将更新放入一个队列中,在适当的时机统一进行 DOM 的更新。而this.$nextTick
就提供了一种方式,让你能够在 Vue 完成 DOM 更新后执行一些操作。
举个例子,在你修改了某个数据后,可能需要获取到更新后的 DOM 元素的一些信息或者一些 DOM 操作,但是直接在数据修改后获取可能会得到更新前的 DOM 状态,这时候就可以利用this.$nextTick
来确保你的操作在下一次 DOM 更新后执行。
下面是一个示例代码:
// 在某个方法中修改数据
changeData() {this.message = 'Updated message'; // 修改数据this.$nextTick(() => {// 在下一次 DOM 更新后执行的操作const element = document.getElementById('someElement');console.log('Updated DOM:', element.innerText);});
}
在上面的代码中,changeData
方法中先修改了 message
的值,然后在this.$nextTick
方法中传入了一个回调函数。这个回调函数会在下一次 DOM 更新后被调用,在这个时候,你可以放心地获取到更新后的 DOM 状态。
需要注意的是,this.$nextTick
方法是异步执行的,所以不能保证回调函数的执行顺序。如果需要确保多个回调函数的执行顺序,可以在每个回调函数中再次使用 this.$nextTick
。
1.5 Vue封装的过度与动画
过渡与动画的作用是让元素在插入、更新或移除时,能够以平滑的动画效果呈现出来,增强用户体验。通过 Vue 提供的 <transition>
组件,你可以轻松地实现元素的渡效果和动画效果。
1.5.1 详细步骤
-
准备样式
首先,你需要准备好过渡或动画效果所需的样式,其中包括:
- 元素进入时的样式类名:
v-enter
:表示元素进入时的起点状态。v-enter-active
:表示元素进入过程中的状态。v-enter-to
:表示元素进入时的终点状态。
- 元素离开时的样式类名:
v-leave
:表示元素离开时的起点状态。v-leave-active
:表示元素离开过程中的状态。v-leave-to
:表示元素离开时的终点状态。
- 元素进入时的样式类名:
-
使用
<transition>
将需要过渡或动画的元素使用
<transition>
包裹起来,并配置name
属性来指定样式类名的前缀。<transition name="hello"><h1 v-show="isShow">你好啊!</h1> </transition>
在上面的例子中,
name="hello"
表示过渡或动画效果所需的样式类名的前缀为hello
。 -
备注
- 如果需要对多个元素同时进行过渡或动画,可以使用
<transition-group>
,并为每个元素指定唯一的key
值。 - 每个过渡或动画效果都会在适当的时机自动添加和移除对应的样式类名,从而实现动态的过渡效果。
- 如果需要对多个元素同时进行过渡或动画,可以使用
示例代码
假设我们要实现一个元素在显示和隐藏时的淡入淡出效果:
<template><div><button @click="toggle">切换显示</button><transition name="fade"><h1 v-show="isShow">你好啊!</h1></transition></div>
</template><script>
export default {data() {return {isShow: false};},methods: {toggle() {this.isShow = !this.isShow;}}
};
</script><style>
.fade-enter-active, .fade-leave-active {transition: opacity 0.5s;
}
.fade-enter, .fade-leave-to {opacity: 0;
}
</style>
在上面的例子中,当点击按钮时,isShow
的值会切换,从而触发元素的显示和隐藏。同时,<transition>
标签中的 name="fade"
属性表示使用了名为 fade
的样式类名前缀。在样式部分,定义了 .fade-enter-active
、.fade-leave-active
、.fade-enter
和 .fade-leave-to
这几个类,来实现淡入淡出的过渡效果。
1.6 插槽
在 Vue 中,插槽是一种组件间通信的机制,允许父组件向子组件传递 HTML 结构或数据,并在子组件中进行展示或处理。Vue 中的插槽分为默认插槽、具名插槽和作用域插槽三种类型,用于不同的场景。
- 默认插槽:
默认插槽是最简单的一种插槽形式。父组件可以在子组件的标签中插入 HTML 结构或文内容,而子组件通过 <slot>
标签定义插槽的位置,用来展示父组件传递过来的内容。
示例代码:
<!-- 父组件 -->
<Category><div>HTML 结构1</div>
</Category><!-- 子组件 -->
<template><div><slot>插槽默认内容...</slot></div>
</template>
- 具名插槽:
具名插槽允许父组件将内容传递给子组件的指定位置,可以同时存在多个具名插槽。在父组件中,通过 slot
属性指定插槽的名称;在子组件中,通过 <slot>
标签的 name
属性匹配对应的插槽名称。
示例代码:
<!-- 父组件 -->
<Category><template slot="center"><div>HTML 结构1</div></template><template v-slot:footer><div>HTML 结构2</div></template>
</Category><!-- 子组件 -->
<template><div><slot name="center">插槽默认内容...</slot><slot name="footer">插槽默认内容...</slot></div>
</template>
- 作用域插槽:
作用域插槽允许父组件向子组件传递数据,但根据数据生成的结构由子组件的使用者(父组件)决定。在父组件中,通过 <template>
标签的 scope
或 slot-scope
属性声明作用域变量;在子组件中,通过 <slot>
标签的 name
属性接收作用域变量,并根据数据结构进行渲染。
示例代码:
<!-- 父组件 -->
<Category><template scope="scopeData"><ul><li v-for="g in scopeData.games" :key="g">{{ g }}</li></ul></template>
</Category><!-- 子组件 -->
<template><div><slot :games="games"></slot></div>
</template><script>
export default {name: 'Category',data() {return {games: ['红色警戒', '穿越火线', '劲舞团', '超级玛丽']}},
}
</script>
通过插槽机制,父组件和子组件之间可以实现更灵活的交互,使得组件的复用性和扩展性得到了增强。
二: Vuex
在 Vue 中,Vuex 是一种集中式状态管理工具,用于管理应用中的共享状态。它适用于需要多个组件共享数据的场景,可以让组件之间更方便地进行通信和状态管理。
2.1 Vuex 基础
Vuex 将应用的共享状态抽取出来,以一个全局单例模式管理。它包含了以下几个核心概念:
-
State(状态):即应用中需要共享的数据,存储在 Vuex 的状态树中,可以通过
$store.state
访问。 -
Getters(获取器):用于从状态树中派生出一些状态,类似于计算属性,可以通过
$store.getters
访问。 -
Mutations(变更):提交 mutation 是唯一改变状态的方式,每个 mutation 都有一个字符串类型的事件类型和一个回调函数,通过
$store.commit
提交。 -
Actions(动作):类似于 mutations,但是可以提交异步操作,通过
$store.dispatch
分发。 -
Modules(模块):允许将 store 分割成模块,每个模块拥有自己的 state、getters、mutations、actions。
何时使用?
当应用中存在多个组件需要共享状态时,可以考虑使用 Vuex。它可以帮助管理这些共享状态,使得组件之间的通信更加简单明了。
搭建 Vuex 环境
-
创建文件:
src/store/index.js
// 引入 Vue 核心库 import Vue from 'vue' // 引入 Vuex import Vuex from 'vuex' // 应用 Vuex 插件 Vue.use(Vuex)// 准备 actions 对象——响应组件中用户的动作 const actions = {} // 准备 mutations 对象——修改 state 中的数据 const mutations = {} // 准备 state 对象——保存具体的数据 const state = {}// 创建并暴露 store export default new Vuex.Store({actions,mutations,state })
-
在
main.js
中创建 Vue 实例时传入store
配置项// 引入 store import store from './store'// 创建 Vue 实例 new Vue({el: '#app',render: h => h(App),store })
基本使用
-
初始化数据、配置
actions
、配置mutations
,操作文件store.js
// 引入 Vue 核心库 import Vue from 'vue' // 引入 Vuex import Vuex from 'vuex' // 引用 Vuex Vue.use(Vuex)const actions = {// 响应组件中加的动作jia(context, value) {context.commit('JIA', value)}, }const mutations = {// 执行加JIA(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('action中的方法名', 数据)
或$store.commit('mutations中的方法名', 数据)
备注:若没有网络请求或其他业务逻辑,组件中也可以越过 actions,即不写
dispatch
,直接编写commit
。
2.2 Getter 和 4 个 Map方法
2.2.1 Getter 方法
在 Vuex 中,Getter 方法用于从 store 中获取状态,并可以对获取的进行一些加工处理。Getter 方法可以看作 store 的计算属性,当需要从 store 中派生出一些状态时,可以使用 Getter。
使用方式
在 Vuex 的 store 中,通过配置 getters 对象来定义 Getter 方法。Getter 方法收 state 作为第一个参数,可以通过 $store.getters
访问。
示例代码:
// store.jsimport Vue from 'vue'
import Vuex from 'vuex'Vue.use(Vuex)const state = {sum: 0
}const getters = {// Getter 方法:计算 sum 的十倍bigSum(state) {return state.sum * 10}
}export default new Vuex.Store({state,getters
})
在组件中,可以通过 $store.getters.bigSum
来获取并使用这个 Getter 方法返回的值。
<!-- MyComponent.vue --><template><div><p>Sum: {{ $store.state.sum }}</p><p>Big Sum: {{ $store.getters.bigSum }}</p></div>
</template><script>
export {// ...
}
</script>
2.2.2 mapState、mapGetters、mapActions、mapMutations 方法
这些方法是 Vuex 提供的辅助函数,可以简化在组件中与 Vuex 进行交互的代码。它们可以帮助将 Vuex 中的 state、getters、actions 和 mutations 映射到组件的计算属性或方法中。
2.2.2.1 mapState 方法
用于帮助我们将 Vuex 中的 state 映射为组件的计算属性。
import { mapState } from 'vuex'export default {computed: {// 将 state 中的 sum 映射为计算属性 sum...mapState(['sum'])}
}
2.2.2.2 mapGetters 方法
用于帮助我们将 Vuex 中的 getters 映射为组件的计算属性。
import { mapGetters } from 'vuex'export default {computed: {// 将 getters 中的 bigSum 映射为计算属性 bigSum...mapGetters(['bigSum'])}
}
2.2.2.3 mapActions 方法
用于帮助我们将 Vuex 中的 actions 映射为组件的方法。
import { mapActions } from 'vuex'export default {methods: {// 将 actions 中的 increment 映射为组件的方法 increment...mapActions(['increment'])}
}
2.2.2.4 mapMutations 方法
用于帮助我们将 Vuex 中的 mutations 映射为组件的方法。
import { mapMutations } from 'vuex'export default {methods: {// 将 mutations 中的 increment 映射为组件的方法 increment...mapMutations(['increment'])}
}
这些辅助函数使得在组件中使用 Vuex 更加简洁和便捷,可以直接通过映射后的计算属性或方法访问 Vuex 中的状态和操作。
2.3 模块化+命名空间
在 Vue 中,模块化和命名空间是为了更好地组织和管理 Vuex 中的状态、操作和数据而引入的概念。
2.3.1 模块化
模块化是指将 Vuex 的 store 拆为多个模块,每个模块可以包含自己的 state、getters、mutations 和 actions。这样做的目的是将大型的 Vuex 应用拆分为更小、更易于维护的模块,每个模块可以专注于处理特定领域的状态和操作,提高代码的可读性和可维护性。
在 Vuex 中,可以通过在 store 的 modules 选项中注册模块来实现模块化示例代码:
const moduleA = {state: { ... },mutations: { ... },actions: { ... },getters: { ... }
}const moduleB = {state: { ... },mutations: { ... },actions: { ... },getters: { ... }
}const store = new Vuex.Store({modules: {moduleA,moduleB}
})
在组件中使用模化后的 Vuex,需要在读取 state、getters、dispatch actions 和 commit mutations 时指定所属的模块。
2.3.2 命名空间
命名空间是模块化之后的一个概念,它用于区分不同模块中的 state、getters、mutations 和 actions,避免命名冲突。在使用命名空间之前,Vuex 中的所有模块都是在全局命名空间下的,容易造成命名冲突和混乱。
开启命名空间后,每个模块的 state、getters、mutations 和 actions 将只能在自己的命名空间下访问,需要通过模块名来访问。
在 Vuex 中,可以通过在模块配置中设置 namespaced: true
来开启命名空间。
示例代码:
const moduleA = {namespaced: true,state: { ... },mutations: { ... },actions: { ... },getters: { ... }
}const store = new Vuex.Store({modules: {moduleA}
})
在组件中访问命名空间模块的 state、getters、dispatch actions 和 commit mutations 时,需要在调用时指定所属的模块。
// 访问 state
this.$store.state.moduleA.stateName// 访问 getters
this.$store.getters['moduleA/getterName']// 调用 actions
this.$store.dispatch('moduleA/actionName', payload)// 提交 mutations
this.$store.commit('moduleA/mutationName', payload)
通过模块化和命名空间,可以更好地组织和管理 Vuex 中的状态和操作,提高代码的可维护性和可读性,同时避免了命名冲突和混乱。
这篇关于Vue - 5( 11000 字 Vue2 入门级教程)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!