前一天复习
组件通信
1. 父传子
(1) 给子组件以添加html属性的方式, 传值
(2) 在子组件中, 可以通过 props 接收
2. 子传父
(1) 在子组件中, 通过触发事件的同时传值
this.$emit(事件名, 参数, …)
(2) 在父组件中, 给子组件注册对应的事件, 接收参数
@事件名 = ‘fatherFn’
3. 非父子
(1) 先创建一个都能访问到的事件总线 (空的vue实例)
const bus = new Vue()
(2) 在A组件中, 触发bus的自定义事件, 并传值
bus.
e
m
i
t
(
事
件
名
,
参
数
,
.
.
.
.
)
(
3
)
在
B
组
件
中
,
c
r
e
a
t
e
d
中
,
注
册
b
u
s
的
对
应
的
自
定
义
事
件
b
u
s
.
emit(事件名, 参数, ....) (3) 在B组件中, created中, 注册bus的对应的自定义事件 bus.
emit(事件名,参数,....)(3)在B组件中,created中,注册bus的对应的自定义事件bus.on(事件名, 事件处理函数)
slot插槽: 用于定制组件, 可以进行内容分发的
1. 匿名插槽(默认插槽): 没有配置名字的插槽, 没有具体分配的内容, 都会给到匿名插槽
-
具名插槽: 配置了名字的插槽, 可以实现定向分发 (给我的我才要)
(1) 给插槽起名字
(2) 需要用template将分发的内容包裹
(3) 通过 v-slot:插槽名 指定分发给谁
作用域插槽
定义插槽的同时,可疑船只,传递的值可以供分发内容时使用称为作用域插槽
-
给插槽,以添加属性的方式传值
-
添加的属性会被收集到一个对象中去
{title: '江南皮革厂倒闭了', desc: '不错不错'}
-
这个对象,可以再分发内容的时,在template中通过 = 接收的
插槽也可以带有数据
Vue.component('modal', {
template: `
<div>
<h3><slot name="title"></slot></h3>
<p><slot name="content"></slot></p>
<slot name="confirm" value="确定"></slot>
</div>
`
})
作用域插槽的使用
<modal>
<template v-slot:title>温馨提示</template>
<template v-slot:content>你确定也要退出了</template>
<template v-slot:confirm="scope">
<button href="#">{{scope.value}}</button>
</template>
<template v-slot:cancel="scope">
<button href="#">{{scope.value}}</button>
</template>
</modal>
代码演示:
<body>
<div id="app">
<modal title="温馨一波">
<template v-slot:main="obj">
<p>江南水厂开张了</p>
<p>{{ obj.desc }}</p>
</template>
<template v-slot:default="obj">
<button>{{ obj.yes }}</button>
<button>{{ obj.no }}</button>
</template>
</modal>
</div>
<script src="./vue.js"></script>
<script>
// 插槽: 匿名插槽 具名插槽
// 其实定义插槽的同时, 是可以传值的, 传递的值, 可以供分发内容时使用 (作用域插槽)
// 1. 给插槽, 以添加属性的方式, 传值
// 2. 添加的属性会被收集到一个对象中去
// { title: '江南皮革厂倒闭了', desc: '不错不错' }
// 3. 这个对象, 可以在分发内容时, 在template中通过 = 接收的
Vue.component('modal', {
template: `
<div class="modal">
<div class="header">
<h3>{{ title }}</h3>
</div>
<div class="main">
<slot name="main" title="江南皮革厂倒闭了" desc="不错不错"></slot>
</div>
<div class="footer">
<slot money="100" desc="你好" :yes="yesBtn" :no="noBtn"></slot>
</div>
</div>
`,
data () {
return {
yesBtn: '确认',
noBtn: '取消'
}
},
props: ['title']
})
const vm = new Vue({
el: '#app',
data: {
msg: 'hello vue'
}
})
</script>
</body>
单页应用程序与路由
SPA -单页应用程序
- SPA:
Single Page Application
单页面应用程序 - MPA :
Multiple Page Application
多页面应用程序
优势
- 传统的多页面应用程序,每次请求服务器返回的都是一整个完整的页面
- 单页面应用程序只有第一次会加载完整的页面
- 以后每次请求仅仅获取必要的数据,减少了请求体积,加快页面响应速度,降低了对服务器的压力
- SPA更好的用户体验,运行更加流畅
缺点
- 开发成本高 (需要学习路由)
- 不利于 SEO 搜索引擎优化
ssr: 服务端渲染(前后端分离)(nodejs) 大前端 vue react
路由介绍
- 路由 : 是浏览器 URL 中的哈希值( # hash) 与 展示视图内容 之间的对应规则
- 简单来说,路由就是一套映射规则(一对一的对应规则), 由开发人员制定规则.-
- 当 URL 中的哈希值(
#
hash) 发生改变后,路由会根据制定好的规则, 展示对应的视图内容(组件)
- 为什么要学习路由?
- 渐进式 =>vue => vuer-router (管理组件之间的跳转)
- 在 web App 中, 经常会出现通过一个页面来展示和管理整个应用的功能.
- SPA 往往是功能复杂的应用,为了有效管理所有视图内容,前端路由 应运而生.
- vue 中的路由 : 是 hash 和 component 的对应关系, 一个哈希值对应一个组件
vue-router
基本使用
- 安装
yarn add vue-router
// 或者
npm i vue-router
- 引入路由 文件
<script src="vue.js"></script>
<script src="vue-router.js"></script>
- 创建路由并且挂载到vue实例
const router = new VueRouter()
const vm = new Vue({
el: '#app',
data: {
msg: 'hello vue'
},
router
})
具体步骤
实现vue的具体步骤
- 配置路由规则 hash值和组件的映射规则
- 准备路由规则需要的组件配置对象
- 配置路由的显示出口
配置路由规则
// router 是整个的大的路由实例,一个项目一般就一个(唯一)
// routes 一条路由规则,标记了hash值和组件的对应关系
// {path: 路径, component: 组件配置对象}
const router = new VueRouter({
// 配置路由的规则
routes: [
{ path: '/one', component: One },
{ path: '/two', component: Two }
]
})
准备路由规则需要的组件配置对象
const One = {
template: ` <div> 子组件 one </div> `
}
const Two = {
template: ` <div> 子组件 one </div> `
}
配置路由的出口,显示位置(<router-view></router-view>
)
// router-view 决定了匹配的组件在哪里显示
<div id="app">
<h1>{{ msg }}</h1>
<router-view></router-view>
</div>
代码实现:
<body>
<!--
路由的基本使用:
1. 下载 npm i vue-router
2. 引包
3. 创建路由实例
4. 将路由实例 和 vue实例相关联
挂载到vue实例上
-->
<div id="app">
{{ msg }}
</div>
<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
<script>
// 只要引入了 vue-router, 全局就有一个 VueRouter 构造函数
const router = new VueRouter()
const vm = new Vue({
el: '#app',
data: {
msg: 'hello vue'
},
router
})
</script>
</body>
vue-router 实现单页应用程序代码演示:
<body>
<!--
路由的基本使用:
1. 下载 npm i vue-router
2. 引包
3. 创建路由实例
4. 将路由实例 和 vue实例相关联
挂载到vue实例上
-----------------------------------------
5. 配置路由规则
{ path: ..., component: ... }
6. 准备路由规则中需要的组件配置对象
7. 准备路由出口 (就是指匹配到的路由组件, 展示到哪去)
router-view
-->
<div id="app">
<h1>{{ msg }}</h1>
<!-- 路由出口, 匹配到的路由组件, 展示的位置 -->
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
<script>
// Vue.component(组件名, 组件的配置对象)
// 路由: 是浏览器地址栏路径中的hash值 和 页面组件的对应规则
// 需求: 实现首页, 音乐, 我的朋友, 三个页面的单页切换
// 只要引入了 vue-router, 全局就有一个 VueRouter 构造函数
// router 是整个的大的路由实例, 一个项目一般就一个 (唯一)
// route 一条路由规则, 标记了hash值和组件的对应关系
// { path: 路径, component: 组件配置对象 }
// Home的组件对象
const Home = {
template: `<div>首页</div>`
}
const Music = {
template: `<div>音乐</div>`
}
const Friends = {
template: `<div>好朋友</div>`
}
const router = new VueRouter({
routes: [
{ path: '/home', component: Home },
{ path: '/music', component: Music },
{ path: '/friends', component: Friends }
]
})
const vm = new Vue({
el: '#app',
data: {
msg: 'hello vue'
},
router
})
/*
小结: vue-router的使用步骤,
1. 下载 npm i vue-router
2. 引包
3. 创建路由实例
const router = new VueRouter()
4. 和vue实例相关联, 挂载到vue实例上
---------------------------------------------
5. 配置路由规则
const router = new VueRouter({
routes: [
{ path: 路径, component: 组件配置对象 },
...
]
})
6. 准备规则中需要的组件配置对象
7. 准备路由出口
router-view 决定了匹配的组件在哪里显示
*/
</script>
</body>
路由导航
<router-link></router-link> //导航链接,用于跳转切换路由
1、实际渲染出来,就是 a 标签
2、必须配置 to 属性,表示跳转的路由
<!-- 使用 router-link 组件来导航. -->
<!-- 通过传入 `to` 属性指定链接. -->
<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
<router-link to="/foo">Go to Foo</router-link>
<router-link to="/bar">Go to Bar</router-link>
代码演示:
<body>
<div id="app">
<!-- router-link 导航链接, 用于跳转切换路由
1. 实际渲染出来, 就是 a 标签
2. 必须配置 to 属性, 表示跳转的路由
-->
<h1>xx云音乐</h1>
<ul>
<li><router-link to="/home">首页</router-link></li>
<li><router-link to="/music">音乐</router-link></li>
<li><router-link to="/friends">好朋友</router-link></li>
</ul>
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
<script>
const Home = {
template: `<div>首页</div>`
}
const Music = {
template: `<div>音乐</div>`
}
const Friends = {
template: `<div>好朋友</div>`
}
const router = new VueRouter({
routes: [
{ path: '/', redirect: "/home" },
{ path: '/home', component: Home },
{ path: '/music', component: Music },
{ path: '/friends', component: Friends }
]
})
const vm = new Vue({
el: '#app',
data: {
msg: 'hello vue'
},
router
})
</script>
</body>
导航高亮
- 点击导航 => 元素里添加了两个类
<a href="#/one" class="router-link-exact-active router-link-active">One</a>
<a href="#/two" class="">Two</a>
- 修改方式1 : 直接修改类的样式
.router-link-exact-active,
.router-link-active {
color: red;
font-size: 50px;
}
- 修改方式2 : 使用存在过的类样式 => 修改默认高亮类名
const router = new VueRouter({
routes: [],
// 修改默认高亮的a标签的类名
// red 是已经存在过的
linkActiveClass: 'red'
})
精确匹配和模糊匹配
- 精确匹配 : router-link-exact-active 类名 : 只有当
浏览器地址栏中的哈希值 与 router-link 的 to 属性值,完全匹配对,才会添加该类
- 模糊匹配: router-link-active 类名 : 只要
浏览器地址栏中的哈希值
包含 router-link 的 to 属性值,就会添加该类名 - 解决办法 : 加个 exact
<router-link to="/" exact>
One
</router-link>
- 注意 : 精确匹配和模糊匹配,只对添加类名这个机制有效,与路由的匹配规则无关!!!
代码演示:
<style>
/* router-link-exact-active router-link-active */
/*
1. router-link-active 模糊匹配
router-link中to的路径, 只要在地址栏中包含即可
to="/home" => /home /home/aa /home/bb /home/user
2. router-link-exact-active 精确匹配
router-link中to的路径, 必须和地址栏的路径相同
to="/home" => 只能匹配 /home
*/
.router-link-exact-active {
color: red;
font-size: 30px;
}
</style>
</head>
<body>
<div id="app">
<!-- router-link 导航链接, 用于跳转切换路由
1. 实际渲染出来, 就是 a 标签
2. 必须配置 to 属性, 表示跳转的路由
-->
<h1>xx云音乐</h1>
<ul>
<li><router-link to="/home">首页</router-link></li>
<li><router-link to="/music">音乐</router-link></li>
<li><router-link to="/friends">好朋友</router-link></li>
</ul>
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
<script>
const Home = {
template: `<div>首页</div>`
}
const Music = {
template: `<div>音乐</div>`
}
const Friends = {
template: `<div>好朋友</div>`
}
const router = new VueRouter({
routes: [
{ path: '/', redirect: "/home" },
{ path: '/home', component: Home },
{ path: '/music', component: Music },
{ path: '/friends', component: Friends }
]
})
const vm = new Vue({
el: '#app',
data: {
msg: 'hello vue'
},
router
})
</script>
</body>
路由重定向
- 解释:将
/
重定向到/home
{ path: '/', redirect: '/home' }
编程式导航
除了使用
<router-link>
创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现路由的跳转比如:登录成功了,需要跳转到首页
声明式导航
<router-link to="/index"></router-link>
编程式导航
在 Vue 实例内部,你可以通过 $router
访问路由实例。因此你可以调用 this.$router.push
methods: {
login() {
this.$router.push('/index')
}
}
代码演示:
<style>
.router-link-exact-active {
color: red;
font-size: 30px;
}
</style>
</head>
<body>
<div id="app">
<h1>xx云音乐</h1>
<ul>
<li><router-link to="/home">首页</router-link></li>
<li><router-link to="/music">音乐</router-link></li>
<li><router-link to="/friends">好朋友</router-link></li>
<li><router-link to="/login">登录</router-link></li>
</ul>
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
<script>
// 实际工作中的跳转路由:
// 1. 通过 router-link, 点击导航链接, 跳转路由 (声明式导航) a 链接
// 2. 通过 js 的方式, 跳转 (编程式导航) location.href="xxx.html"
// this.$router.push(路由路径) 去对应的路由路径
// this.$router.go(-1) 返回上一页
const Home = {
template: `<div>首页</div>`
}
const Music = {
template: `<div>音乐</div>`
}
const Friends = {
template: `<div>好朋友</div>`
}
const Login = {
template: `<div>
<input type="text"/> <br/><br/>
<input type="text"/> <br/><br/>
<button @click="fn">登录</button>
</div>`,
methods: {
fn () {
// console.log('嘎嘎')
this.$router.push('/home')
console.log(this.$router === router)
}
}
}
const router = new VueRouter({
routes: [
{ path: '/', redirect: "/home" },
{ path: '/home', component: Home },
{ path: '/music', component: Music },
{ path: '/friends', component: Friends },
{ path: '/login', component: Login }
]
})
const vm = new Vue({
el: '#app',
data: {
msg: 'hello vue'
},
router
})
</script>
</body>
动态路由匹配
我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。
比如:文章列表的展示,文章的id不同,展示的文章内容就不同,但是组件是同一个
/product/1 Product
/product/2 Product
/product/10086 Product
没有动态路由参数的实现方式
动态路由参数的配置语法
动态路由参数的匹配规则
动态路由参数的获取
动态路由参数的使用
const Article = {
template: '<div>文章内容</div>'
}
const router = new VueRouter({
routes: [
// 动态路径参数 以冒号开头
// 可以匹配: /article/1 /article/2 /article/xxx
{ path: '/article/:id', component: Article },
// 如果在动态的路由参数中使用了?,表示该路由参数可选
// 可以匹配 /article /article/1 /article/2
{ path: '/article/:id?', component: Article },
]
})
动态路由参数的获取
const User = {
template: '<div>User {{ $route.params.id }}</div>'
}
代码演示:
<body>
<div id="app">
<ul>
<li><router-link to="/product/1">商品1</router-link></li>
<li><router-link to="/product/2">商品2</router-link></li>
<li><router-link to="/product/3">商品3</router-link></li>
</ul>
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
<script>
// this.$router 整个的大的路由实例, 一个应用就一个 === router
// this.$route 当前路由的相关信息
// $route:
// 1. fullPath 完整的路径(带上查询参数) ?username=pp&password=123456
// 2. path 路径
// 3. query 解析过的查询参数
// 4. params 动态路由参数的信息
// 用同一个组件
const Product = {
template: `
<div>我是商品组件</div>
`,
data() {
return {
msg: '张三'
}
},
created () {
// 获取路由相关的参数信息 (路径, 参数) => this.$route
// 测试的时候
console.log(this.$route.params.id)
console.log(this.$route)
},
watch: {
// 监视路由信息的变化
$route () {
console.log(this.$route.params.id)
}
}
}
// 创建路由
// 有场景: 我们需要将多个路由的情况, 匹配到同一个组件, 比如不同id的商品, 需要用同一个组件解析
// 动态路由匹配
// '/product/:id' 可以匹配 /product/1 /product/2 .... /product/10086
// 不能匹配 /product /product/1/2 (path: '/product/:id1/:id2')
const router = new VueRouter({
routes: [
{ path: '/product/:id', component: Product }
]
})
const vm = new Vue({
el: '#app',
data: {
msg: 'hello vue'
},
router
})
</script>
</body>
letao案例
次案例源文件已上传至资源,文件名称叫做letao案例-Vue第8天.zip