





mounted()中是可以进行异步操作的啊,所以才可以让这种自定义事件更灵活
另外:既然是事件,那么也可以使用事件修饰符:prevent、stop、once



说在beforeDestroy中,会销毁子组件和自定义事件


子组件是如下的样子

1、在ref属性实现的方式中,关于this的指向问题






2、组件使用原生DOM事件的坑【 ps:了解native修饰符,学后端的人看源码的时候,对这个修饰符再熟悉不过了 】




自定义事件是一种组件间通信的方式,适用于:子组件 ——> 父组件通信
使用场景:想让子组件给父组件传递数据时,就在父组件中给子组件绑定自定义事件【 ps:事件回调在父组件methods / 其他地方 中 】,而要解绑自定义事件就找子组件本身
绑定自定义事件:
1、在父组件中:<Person @zixieqing="demo"/> 或 <Person v-on:zixieqing="demo"/>
2、在父组件中:
<Person ref = "demo"/> .........methods: { test(){......}} .........mounted(){ this.$refs.demo.$on('eventName',this.test)}3、若想让自定义事件只能触发一次,可以使用once修饰符【 ps:使用v-on的方式实现的那种 】 或 $once【 ps:使用ref属性实现方式的那种 】
触发自定义事件: this.$emit('eventName',sendData) 【 ps:给谁绑定自定义事件,就找谁去触发 】
解绑自定义事件:this.$off(['eventName',.......]) 【 ps:给谁绑定自定义事件,就找谁解绑;另:注意解绑事件是单个、多个、全解的写法 】
组件上也可以绑定元素DOM事件,但是:需要使用native修饰符
注意项:通过this.$refs.xxxx.$on('eventName',回调)绑定自定义事件时,回调要么配置在父组件的methods中,要么用兰姆达表达式【 ps:或箭头函数 】,否则:this执行会出现问题
VueComponent.prototype._ _proto _ _ === Vue.prototype从而实现出来的一个开发技巧
但是:现在把思路换一下来实现它

通过上面的分析图了解之后,就可以分析出:单独选取的那个组件需要具有如下的特性:
1、那么为了实现第一步:能够让所有的组件都看得到可以怎么做?



VueComponent.prototype._ _proto _ _ === Vue.prototype,即:公共组件选为Vue实例对象vm,这个诶之关系怎么来的,这里不再说明了,在基础篇VueComponent()中已经说明过了,利用此内置关系就是利用:VueComponent可以获取Vue原型上的属性和方法,同时选取了Vue实例对象之后,\(on()、\)emit()、$off()都可以调用了,这些本来就是Vue的内置函数啊,Vue实例对象还没有这些函数吗实例演示:




全局事件总线又名GlobalEventBus
它是一种组件间的通信方式,可以适用于任何组件间通信
全局事件总线的玩法:
1、安装全局事件总线
new Vue({ ....... beforeCreate(){ Vue.prototype.$bus = this }, ...... })2、使用事件总线
发送数据:this.$bus.$emit('EventName',sendData)
接收数据:A组件想接收数据,则:在A组件中给$bus绑定自定义事件,把事件的回调放到A组件自身中【 ps:靠回调来得到数据 】
// 使用methods也行;不使用,把回调放到$on()中也可以【 ps:推荐使用methods,因为不必考虑$on()中的this问题 】 methods: { sendData(){ ...... } }, ........ mounted(){ this.$bus.$on('eventName',receiveData) }, ....... beforeDestroy(){ this.$bus.$off([ 'eventName' , ..... ]) }什么是消息订阅与发布?
基础代码


1、给项目安装pubsub-js库,指令:npm install pubsub-js

2、消息发布方
2.1、引入pubsub-js库
2.2、使用publish( 'msgName' , sendData )这个API进行数据发送

3、消息接收方

4、效果如下

它是一种组件间通信的方式,适用于:任意组件间通信
使用步骤:
1、安装pubsub-js 指令:npm install pubsub-js
2、消息接收方、发送方都要引入pubsub 代码;:import pubsub from "pubsub-js"
数据发送方:pubsub.publish('msgName',sendData)
数据接收方:
// methods可写可不写【 ps:推荐写,不用考虑this的指向问题,和自定义事件一样的 】methods: { demo(){.....}}........mounted(){ // 使用this.msgName把每条订阅都绑在组件实例对象vc上,方便取消订阅时获取到这个订阅id this.msgName = pubsub.subscribe('msgName', callback) // 如果不写methods,那么回调就写在这里,注意:使用箭头函数}.......beforeDestroy(){ pubsub.unsubscribe( this.msgName )}1、基础代码



需求、让食品分类中显示具体的一张食品图片、让电影分类中电视某一部具体的电影,使用默认插槽改造

<template> <div > <Category title = "食品"> <!-- 2、将内容套在组件标签里面从而携带到slot处 此种方式:是vue在解析完App这个组件的模板时, 将整个组件中的内容给解析完了,然后放到了Category组件里面使用slot占位处 所以:slot所放位置 和 这里面代码解析之后放过去的位置有关 另外:由于是先解析完APP组件中的东西之后 再放到 所用组件里面slot处的位置 因此:这里可以使用css+js,这样就会让 模板 + 样式解析完了一起放过去 不用css+js就是先把模板解析完了放过去,然后找组件里面定义的css+js --> <img src="./assets/food.png" alt="照片开小差去了"> </Category> <Category title = "游戏"> <ul> <li v-for=" (game,index) in games" :key="index">{{game}}</li> </ul> </Category> <Category title = "电影"> <video controls src="./assets/枕刀歌(7) - 山雨欲来.mp4"></video> </Category> </div> </template> <script> import Category from "./components/Category.vue" export default { name: 'App', components: {Category}, data() { return { foods: ['紫菜','奥尔良烤翅','各类慕斯','黑森林','布朗尼','提拉米苏','牛排','熟寿司'], games: ['王者荣耀','和平精英','英雄联盟','文明与征服','拳皇','QQ飞车','魔兽争霸'], filems: ['无间道','赤道','禁闭岛','唐人街探案1','肖申克的救赎','盗梦空间','无双'] } }, } </script> <style> .container { display: flex; justify-content: space-around; } img,video { width: 100%; } </style>
需求、在电影分类的底部显示"热门"和"悬疑"



基础代码



需求:多个组件一起使用,数据都是一样的,但是有如下要求:
开始改造代码:






既然作用域插槽会玩了,那就实现需求吧



另外:父组件接收数据时的scope还有一种写法,就是使用slot-scope

1、作用:让父组件可以向子组件指定位置插入HTML结构,也是一种组件间通信的方式,适用于:父组件 ===》 子组件
2、分类:默认插槽、具名插槽、作用域插槽
3、使用方式
1)、默认插槽
// 父组件 <Category> <div> HTML结构 </div> </Category> // 子组件 <template> <div> <!-- 定义插槽 --> <slot>插槽默认内容</slot> </div> </template>2)、具名插槽
// 父组件 <template> <!-- 指定使用哪个插槽 --> <Category slot = "footer">也可以加入另外的HTML结构</Category> </template> // 子组件 <template> <div> <!-- 定义插槽 并 起个名字--> <slot name = "footer">插槽默认内容</slot> </div> </template>3)、作用域插槽
// 子组件 <template> <div > <h3>{{title}}分类</h3> <!-- 作用域插槽 1、子组件( 传递数据 ) 提供一个路口,把父组件想要的数据传给它【 ps:有点类似于props的思路,只是反过来了 】 :filems中的filems就是提供的路,给父组件传想要的东西【 ps:对象、数据都行 】 --> <slot :filems = "filems">这是默认值</slot> </div> </template> <script> export default { name: 'Category', props: ['title'], data() { // 数据在子组件自身中 return { filems: ['无间道','赤道','禁闭岛','唐人街探案1','肖申克的救赎','盗梦空间','无双'] } }, } </script> // 父组件 <template> <div > <Category title = "电影"> <!-- 2、父组件( 接收数据 ) 前面说的 多了一个要求 就是这里"必须用template标签套起来" 怎么接收?使用scope="xxxx"属性 xxx就是接收到的数据,这个名字随便取 这个名字不用和子组件中用的 :filems 这个filems这个名字保持一致,因:它接收的就是这里面传过来的东西 但是:这个数据有点特殊,需要处理一下 --> <template scope="receiveData"> <!-- {{receiveData}} --> <!-- 拿到了数据,那"页面的结构就可以随插槽的使用者随便玩"了 --> <ul> <li v-for="(filem,index) in receiveData.filems" :key="index">{{filem}}</li> </ul> </template> </Category> <Category title = "电影"> <!-- ES6中的"结构赋值"简化一下 --> <template scope="{filems}"> <ol> <li v-for="(filem,index) in filems" :key="index">{{filem}}</li> </ol> </template> </Category> <Category title = "电影"> <!-- ES6中的"结构赋值"简化一下 --> <template scope="{filems}"> <h4 v-for="(filem,index) in filems" :key="index">{{filem}}</h4> </template> </Category> <!-- scope还有一种写法 使用slot-scope--> <Category title = "电影"> <!-- ES6中的"结构赋值"简化一下 --> <template slot-scope="{filems}"> <h4 v-for="(filem,index) in filems" :key="index">{{filem}}</h4> </template> </Category> </div> </template> <script> import Category from "./components/Category.vue" export default { name: 'App', components: {Category}, } </script>

1、在项目中安装vuex 指令:npm install vuex
2、编写store

3、让store在任意组件中都可以拿到


vuex环境搭建小结
1、创建文件src/store/index.js
// 引入vuex import vuex from "vuex" // 使用vuex —— 需要vue 所以引入vue import Vue from "vue" Vue.use(vuex) // 创建store中的三个东西actions、mutations、state const actions = {} const mutations = {} const state = {} // 创建store ———— 和创建vue差不多的套路 export default new vuex.Store({ // 传入配置项 ———— store是actions,mutations,state三者的管理者,所以配置项就是它们 actions, // 完整写法 actions:actions ,是对象嘛,所以可以简写 mutations,state })2、在main.js中配置store
import App from "./App.vue" import Vue from "vue" // 引入store import store from "./store" // 由于起的名字是index,所以只写./store即可,这样默认是找index,没有这个index才报错 const vm = new Vue({ render: h=>h(App), components: {App}, // 让store能够被任意组件看到 ———— 加入到vm配置项中【 ps:和全局事件总线很像 】 store, template: `<App></App>`, }).$mount('#app') 1、先把要操作的数据 / 共享数据放到state中


2、在组件中使用dispatch这个API把key-value传给actions


2、actions接收key-value【 ps:要是有逻辑操作,也放在这里面,ajax也是 】


3、mutations接收key-value




4、查看开发者工具【 ps:简单了解,自行万一下 】
另外:vuejs devtools开发工具版本不一样,则:页面布局也不一样,但是:功能是一样的

当然:前面说过,直接在组件中调commit这个API从而去和mutations打交道,这种是可以的,适用于:不需要逻辑操作的过程,示例就自行完了
以上便是简单了解vuex,前面的例子看起来没什么用,但是vuex这个东西其实好用得很




1、改造源代码 —— 使用计算属性实现


2、使用mapState改造获取state中的数据,从而生成计算属性
import {mapState} from "vuex"

...mapState({sum:'sum'})这里面的sum:'sum'这两个是一样的,那么:一名多用

3、使用mapGetters把getters中的东西生成为计算属性
import {mapState,mapGetters} from "vuex"


1、mapActions —— 调的API就是dispatch

import {mapActions} from 'vuex'





2、mapMutations —— 这个和mapActions一模一样,只是调用的API是commit

1、在state中再加一点共享数据

2、新增Person组件



3、共享数据
操作如下:


npm install vue-router来进行安装,这个东西就是专门用来做单页面网站应用的一个完整的页面、点击页面中的导航链接不会刷新页面,只会做页面的局部刷新、数据需要通过ajax请求获取npm install vue-router来进行安装,这个东西就是专门用来做单页面网站应用的一个完整的页面、点击页面中的导航链接不会刷新页面,只会做页面的局部刷新、数据需要通过ajax请求获取1、准备工作:

2、开始玩路由器 router
1)、给项目安装路由 指令:npm install vue-router
2)、在main.js中引入并使用路由器【 ps:路由器是一个插件 】

3)、编写组件

4)、配置路由器【 ps:这也叫配置路由规则,就是key-value的形式,在前端中,key是路径,value是组件 】

5)、把配置的路由规则引入到main.js中

6)、在静态页面中使用路由【 ps:需要记住两个标签 <router-link ..... to = "路径名"></router-link> 和 <router-view></router-view> ]
<router-link ..... to = "路径名"></router-link> 是指:跳转 其中:路径名 就是 路由规则中配置的 path 参照a标签来理解 本质就是转成了a标签
<router-view></router-view> 是指:视图显示 就是告知路由器 路由规则中配置的component应该显示在什么位置,和slot插槽一样,占位

页面结构源码如下:
<template> <div> <div > <div > <div > <h2>Vue Router Demo </h2></div> </div> </div> <div > <div > <div > <router-link active- to="./about">About</router-link> <router-link active- to="./home">Home</router-link> <!--对照a标签 <a href="./home.html">Home</a> --> </div> </div> <div > <div > <div > <router-view></router-view> </div> </div> </div> </div> </div> </template> <script> export default { name: 'App', } </script>7)、运行效果如下:

另外:从此处开始,可以先摸索Element-ui组件库了,这是专门搭配vue来做页面的网站 和 bootstrap一个性质,这个东西后续要用,网址如下:

vue-router使用小结
1、安装vue-router ,命令:npm install vue-router
2、在main.js中 指令:import VueRouter from "vue-router"
3、应用vue-router插件,指令:Vue.use(VueRouter)
4、编写router路由规则
// 引入路由器 import VueRouter from "vue-router" // 引入需要进行跳转页面内容的组件 import About from "../components/About.vue" import Home from "../components/Home.vue" // 创建并暴露路由器 export default new VueRouter({ routes: [ // 路由器管理的就是很多路由 所以:routes 是一个数组 { // 数组里面每个路由都是一个对象 它有key和value两个配置项【 ps:还有其他的 】 path: '/about', // 就是key 也就是路径名,如:www.baidu.com/about这里的about component: About // 就是value 也就是组件 },{ path: '/home', component: Home }, ] })5、实现切换( active-class 可配置高亮样式 )
<router-link active- to="./about">About</router-link>6、指定展示位置
<router-view></router-view>
$route属性,里面存储这自己的路由信息

$router属性获取到【 ps:验证自行把不同组件的这个东西绑定到window对象上,然后等路由组件挂载完毕了,拿到它们进行比对,答案是:false 】
1、在src/page下再新建两个路由组件

2、给home路由规则编写多级路由

3、重新编写Hmoe.vue路由组件

源码如下:
<template> <div> <h2>我是Home的内容</h2> <div> <ul > <li> <!-- 多级路由,这里的to后面需要加上父级路径 先这么写,它可以简写,后续进行处理 --> <router-link active- to="/home/news">News</router-link> </li> <li> <router-link active- to="/home/message">Message</router-link> </li> </ul> <ul> <router-view></router-view> </ul> </div> </div> </template> <script> export default { name: 'Home' } </script>4、运行效果如下

1、query的字符串传参写法【 ps:也就是路径传参嘛,适合传递少量参数 】




2、query的对象写法 【 ps:适合传递大量参数 】


实例:



命名路由小结
作用:简化路由跳转时的path写法
使用:
给命令命名
{ path: '/home', component: Home, children: [ { path: 'news', component: News },{ path: 'message', component: Message, children: [ { path: 'detail', // 使用另一个配置项name 命名路由,从而让path更精简 name: 'detail', component: Detail } ] }, ] },简化路由跳转写法
<!-- 简化前写法 --> <router-link :to="{ path: '/home/message/detail', query: { id: m.id, title: m.title } }"> {{m.title}} </router-link> <!-- 简化后写法 --> <router-link :to="{ name: 'detail', query: { id: m.id, title: m.title } }"> {{m.title}} </router-link>1、使用params传递参数【 ps:数据的传递者 】,这一步和以前的query传递没什么两样,只是改了一个名字而已




路由params传参小结
1、配置路由
{ path: '/home', component: Home, children: [ { path: 'news', component: News },{ path: 'message', component: Message, children: [ { // 使用params传参,则:需要把path的规则改了,就是占位,接对应参数 path: 'detail/:id/:title', name: 'detail', // 对象写法,必须保证有这个配置项 component: Detail } ] }, ] }, 2、传递参数
<!-- 使用params传递参数 --> <!-- 字符串写法 --> <router-link :to="`/home/message/detail/${m.id}/${m.title}`"> {{m.title}} </router-link> <!-- 对象写法 这种写法必须保证里面是name,而不是params,否则:页面内容会丢失的 --> <router-link :to="{ name: 'detail', params: { id: m.id, title: m.title } }"> {{m.title}} </router-link>注意点:路由携带params参数时,若使用的to的对象写法,则:不能使用path配置项,必须用name配置项
3、接收参数
{{$route.params.id}} {{$route.params.title}}
1、布尔值写法
为true时,则把path接收到的所有params参数以props的形式发给所需路由组件, 如:这里的Detail

2、函数写法

3、另外的方式
this.$route.queru / params.xxxx 代码量大的话,这不就还得多写N多this吗



router-link的replace属性小结
push和replace,其中:push是追加历史记录,replace是替换当前记录,路由跳转时默认为push<router-link replace ......>News</router-link>router-link来实现路由跳转,前面玩了$route,而现在就是来玩的$router$router这个东西,顺便知道掌握哪些API,就是下图中的五个
1、玩一下push和replace这两个API


2、玩一下back和forward这两个API


3、玩一下go这个API


<keep-alive include = "componentName"></keep-alive>标签来实现1、缓存一个路由组件 —— 字符串写法





2、缓存多个路由组件 —— 数组写法

1、另一对生命钩子
keep-alive include = "xxx"保留改组件,切换后不让其销毁【 ps:beforeDestroy不起作用了 】,那么:又想要最后关掉定时器之类的,就可以使用这两个钩子函数

2、另外一个钩子函数就是nextTick










实例:






?





1、编写完了程序之后打包项目
npm run serve,在脚手架时就说过还有一个命令:npm run build,那时说过:后端要的前面资源是HTML+CSS+JS,所以此时项目打包就需要用到它了

2、使用node+express框架编写一台小服务器模拟一下上线
自行新建一个文件夹,然后使用vscode打开
1)、让文件夹变成合法包 指令:npm init

2)、安装express 指令:npm install express 注意:这一步很容易因为自己当初配置nodejs时操作不当,导致权限不够啊,就会报一堆warn和error

3)、新建一个js文件,编写内容如下

源码如下:
// 1、引入express 注意:这里就不是ES6的模块化了,而是commanjs模块化 const express = require('express') // 2、创建一个app服务实例对象 const app = express() // 3、端口号监听 app.listen(8001,(err)=>{ // err是一个错误对象 if( !err ) console.log("服务器启动成功"); }) // 4、配置一个后端路由 app.get('/person',(req,res)=>{ // req就是request res就是response res.send({ name: '紫邪情', age: 18 }) })4)、启动服务器 指令:node server

5)、访问服务器中的端口测试一下

3、准备工作弄完了,现在把刚刚使用npm run build打包的dist中的文件复制到服务器中去

4、让复制进去的文件能够被服务器认识

node server 开始演示路由器的两种工作模式的另一个坑【 ps:别忘记有个权限认证啊,在缓存把对应东西放上,不然有些路由组件点不了 】

http://localhost:8001/home/news中的/home/news,服务器中那有这个资源,所以:404呗




Vue2到此结束,另外还有一些Vue UI组件库
接下来的技术点就是:Vue3