1、复习
(1).sync修饰符原理解析
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<child :childmsg="msg" @update:childmsg="changeTitle">
</child>
</div>
<script src="./vue.js"></script>
<script>
const vm = new Vue({
el: '#app',
data: {
msg: 'parent data'
},
methods: {
changeTitle(data) {
this.msg = data
}
},
components: {
child: {
template: `
<div>子组件:{{ childmsg }} <button @click="fn">改变props</button></div>
`,
props: ['childmsg'],
methods: {
fn() {
this.$emit('update:childmsg', '新值')
}
}
}
}
})
</script>
</body>
</html>
(2)props是只读的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<child :childmsg="msg"></child>
</div>
<script src="./vue.js"></script>
<script>
// 2 props 是只读的,不能修改。
// 不能修改是说:不能重新赋值
const vm = new Vue({
el: '#app',
data: {
msg: 'parent data'
},
components: {
child: {
template: `
<p @click="fn">子组件 -- {{ mymsg }}</p>
`,
props: ['childmsg'],
data() {
return {
mymsg: this.childmsg
}
},
methods: {
fn() {
this.mymsg = 'change'
}
}
}
}
})
</script>
</body>
</html>
(3)实现props双向数据绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<!-- 1 给属性添加 .sync 修饰符 -->
<child :childmsg.sync="msg"></child>
</div>
<script src="./vue.js"></script>
<script>
// 2 props 是只读的,不能修改。
// 不能修改是说:不能重新赋值
const vm = new Vue({
el: '#app',
data: {
msg: 'parent data'
},
components: {
child: {
template: `
<p @click="fn">子组件 -- {{ childmsg }}</p>
`,
props: ['childmsg'],
methods: {
fn() {
// 2 通过 $emit 触发一个特殊形式的事件
// 事件名称: update: + props属性的名称
this.$emit('update:childmsg', '修改后的数据')
}
}
}
}
})
</script>
</body>
</html>
(3)index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<CHILD></CHILD>
</div>
<!-- <P></P>
<DIV></DIV> -->
<script src="./vue.js"></script>
<script>
// 1 HTML 是大小写不敏感的,浏览器会把所有大写字符解释为小写字符
// 说明:这个限制只对 DOM(el) 有效,对 template 选项无效
// 组件名大小写的问题说明:
// https://cn.vuejs.org/v2/guide/components-registration.html
//
// 推荐: 字母全小写,多个单词之间使用连字符分割 my-component
// props 大小写的问题说明:
// https://cn.vuejs.org/v2/guide/components-props.html
//
// 推荐: 字母全小写,多个单词之间使用连字符分割
// 2 props 是只读的,不能修改。
// 不能修改是说:不能重新赋值
//
// 如果是传递的引用类型数据,子组件可以直接修改这个引用类型数据中的属性。
// 如果要给引用类型的数据赋值,也应该通过 .sync 的方式
// 如果是传递的基本类型的,子组件是不能直接给这个数据赋值的!!! 应该通过 .sync 方式来处理
// 3 单向数据流
// 组件之间,父组件的数据通过 props 自动的流向 子组件
// 并且,当父组件的数据发生改变,这个改变后的数据也会自动再流向子组件
//
// 组件之间数据流向是:父 -> 子
// 对于子组件需要使用父组件数据的情况,数据应该是由父组件提供,子组件使用
// 4 json-server 自身不支持批量删除功能,如果要用编码(nodejs)
const vm = new Vue({
el: '#app',
data: {
msg: 'parent data'
},
components: {
CHILD: {
template: `
<p>子组件</p>
`
}
}
})
</script>
</body>
</html>
(5)组件和属性名大小写的问题说明
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<child></child>
</div>
<script src="./vue.js"></script>
<script>
const vm = new Vue({
el: '#app',
data: {},
components: {
child: {
template: `
<div>
<CHILD1 :TITLE="title"></CHILD1>
</div>
`,
data() {
return {
title: '标题党'
}
},
components: {
CHILD1: {
template: `
<div>子zi组件 --- {{ TITLE }}</div>
`,
props: ['TITLE']
}
}
}
}
})
</script>
</body>
</html>
2、开关灯(兄弟组件通讯)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
/* 容器 */
.container {
width: 150px;
}
/* 灯 */
.light {
width: 100px;
height: 100px;
border-radius: 50%;
text-align: center;
line-height: 100px;
margin: 0 auto;
color: #fff;
background-color: #000;
}
/* 开灯 */
.turn-on {
background-color: #ff0;
color: #000;
}
/* 灯座 */
.bottom {
width: 150px;
height: 50px;
margin-top: 10px;
line-height: 50px;
text-align: center;
color: #fff;
background-color: #000;
}
</style>
</head>
<body>
<div id="app" class="container">
<light-head></light-head>
<light-bottom></light-bottom>
</div>
<script src="./vue.js"></script>
<script>
// 1 创建bus
const bus = new Vue()
// light-bottom 发送数据 - 触发事件
// light-head 接受数据 - 注册事件
Vue.component('light-head', {
template: `
<div class="light" :class="{ 'turn-on': isOn }">
我是一盏灯
</div>
`,
data() {
return {
isOn: false
}
},
created() {
// 注册事件
bus.$on('light', (data) => {
this.isOn = data
})
}
})
Vue.component('light-bottom', {
template: `
<div class="bottom">
<button @click="turnOn(true)">开</button>
<button @click="turnOn(false)">关</button>
</div>
`,
methods: {
turnOn(data) {
// 触发事件
bus.$emit('light', data)
}
}
})
var vm = new Vue({
el: '#app',
data: {
}
})
</script>
</body>
</html>
3、SPA demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
div {
height: 500px;
width: 100%;
background-color: hotpink;
}
</style>
</head>
<body>
<ul>
<li>
<a href="#/find">发现音乐</a>
</li>
<li>
<a href="#/my">我的音乐</a>
</li>
<li>
<a href="#/friend">朋友</a>
</li>
</ul>
<div id="content">
<!-- 这是内容区域 -->
</div>
<script src="./node_modules/axios/dist/axios.js"></script>
<script type="text/javascript">
// a标签的锚点值是用来实现:页面内部跳转
/*
- 1 ajax
- 2 哈希值(锚点)的使用(window.location.hash #)
- 3 hashchange 事件
*/
// 进入页面,就触发这个函数来获取当前哈希值对应的内容
handlerChange()
window.addEventListener('hashchange', handlerChange)
function handlerChange() {
// console.log('哈希值改变了', location.hash)
switch (location.hash) {
case '#/friend':
axios.get('./friend.json').then(res => {
console.log(res)
document.getElementById('content').innerHTML = `<h1>${res.data.content}</h1><p>${res.data.name}</p>`
})
break;
case '#/my':
axios.get('./my.json').then(res => {
console.log(res)
document.getElementById('content').innerHTML = `<h1>${res.data.content}</h1><p>${res.data.name}</p>`
})
break;
case '#/find':
axios.get('./find.json').then(res => {
console.log(res)
document.getElementById('content').innerHTML = `<h1>${res.data.content}</h1><p>${res.data.name}</p>`
})
break;
}
}
</script>
</body>
</html>
4、a 标签 锚点值的回顾
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<a href="#/mother">小蝌蚪说:妈妈你在哪呢???</a>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<div id="/mother">妈妈在这呢!</div>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
<p>老青蛙</p>
</body>
</html>
5、vue中路由的基本使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<ul>
<li>
<!-- 入口:实际上就是一个a标签 -->
<router-link to="/home">首页</router-link>
</li>
</ul>
<!-- 指定路由出口 -->
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
<script>
// 路由的使用步骤:
// 1 安装: npm i -S vue-router
// 2 引入 vue-router
// 3 创建路由规则
// 4 将路由实例与vue实例关联到一起
// 5 配置路由规则
// 哈希值 和 组件 的对应关系
// 6 指定路由出口( 表示将当前匹配的路由展示在页面中的哪个位置 )
const Home = Vue.component('home', {
template: `
<h1>这是 Home 组件</h1>
`
})
// 创建路由实例
const router = new VueRouter({
routes: [
{ path: '/home', component: Home }
]
})
const vm = new Vue({
el: '#app',
data: {
},
// 将路由与实例关联到一起
router
})
</script>
</body>
</html>
6、Vue中路由的重定向
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<ul>
<li>
<router-link to="/home">首页</router-link>
</li>
</ul>
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
<script>
// 路由匹配展示的过程:
//
// 1 当点击a标签(或者直接修改浏览器地址栏中的哈希值)会改变哈希值
// 2 当哈希值发生改变,Vue路由就会监听到这个变化
// 3 当路由监听到哈希值改变以后,就会用配置好的路由规则来匹配当前的哈希值
// 4 当哈希值被匹配成功,就会将当前路由规则对应的组件展示在页面中 router-view 中
// 路由默认的 path 为: /
const Home = {
template: `
<h1>这是 Home 组件</h1>
`
}
const router = new VueRouter({
routes: [
// 重定向:
// / 是默认的路径,页面第一打开的时候,就会访问这个路径
// 当这个路径匹配成功后,通过指定的 redirect 就可以重定向到其他路由了
{ path: '/', redirect: '/home' },
{ path: '/home', component: Home }
]
})
const vm = new Vue({
el: '#app',
data: {
},
router
})
</script>
</body>
</html>
8、Vue中路由参数 - 1 问题说明
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<ul>
<li>
<router-link to="/home">首页</router-link>
</li>
<li>
<router-link to="/stu/1001">学生 1</router-link>
</li>
<li>
<router-link to="/stu/1002">学生 2</router-link>
</li>
</ul>
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
<script>
// 路由参数:
const Home = {
template: `
<h1>这是 Home 组件</h1>
`
}
const Stu1 = {
template: `
<div>
<p>这是第一个学生 1111</p>
</div>
`
}
const Stu2 = {
template: `
<div>
<p>这是第二个学生 2222</p>
</div>
`
}
const router = new VueRouter({
routes: [
{ path: '/', redirect: '/home' },
{ path: '/home', component: Home },
{ path: '/stu/1001', component: Stu1 },
{ path: '/stu/1002', component: Stu2 },
]
})
const vm = new Vue({
el: '#app',
data: {
},
router
})
</script>
</body>
</html>
9、Vue中的路由参数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<ul>
<li>
<router-link to="/home">首页</router-link>
</li>
<li>
<router-link to="/stu/1001">学生 1</router-link>
</li>
<li>
<router-link to="/stu/1002">学生 2</router-link>
</li>
</ul>
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
<script>
// 路由参数:
const Home = {
template: `
<h1>这是 Home 组件</h1>
`
}
const Stu = {
template: `
<div>
<p>这是第一个学生 {{ $route.params.id }}</p>
</div>
`
}
const router = new VueRouter({
routes: [
{ path: '/', redirect: '/home' },
{ path: '/home', component: Home },
// :id 就是路由参数
// 匹配的哈希值为: /stu/1001 或 /stu/1002 或 /stu/abc
// 无法匹配的哈希值为: /stu 或 /stu/ 或 /stu/1001/ab
{ path: '/stu/:id', component: Stu },
// { path: '/stu/1001', component: Stu1 },
// { path: '/stu/1002', component: Stu2 },
]
})
const vm = new Vue({
el: '#app',
data: {
},
router
})
</script>
</body>
</html>
10、Vue中路由参数 - 说明
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<ul>
<li>
<router-link to="/home">首页</router-link>
</li>
<li>
<router-link to="/stu/1001">学生 1</router-link>
</li>
<li>
<router-link to="/stu/1002">学生 2</router-link>
</li>
</ul>
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
<script>
// 路由参数:
const Home = {
template: `
<h1>这是 Home 组件</h1>
`
}
const Stu = {
template: `
<div>
<p>这是第一个学生 {{ $route.params.id }} -- {{ name }}</p>
</div>
`,
data() {
return {
stuList: {
'1001': '小明',
'1002': '小红'
},
name: ''
}
},
// vue为了高效的渲染组件,如果从 /stu/1001 直接跳转到 /stu/1002 的时候,会复用这个组件
// 这就导致了组件的 created 钩子函数不会再次执行
// 如何解决???通过监听 $route 的变化,来解决
created() {
// console.log('获取到路由参数:', this.$route.params.id)
const id = this.$route.params.id
this.name = this.stuList[id]
},
watch: {
// 监视路由的改变
$route(to, from) {
// from 从哪来,也就是:从哪个路由跳转过来的
// to 到哪去,也就是:也就是要跳转到的路由(也就是当前路由)
// console.log(to)
// console.log('路由参数为:', to.params.id)
const id = to.params.id
this.name = this.stuList[id]
}
}
}
const router = new VueRouter({
routes: [
{ path: '/', redirect: '/home' },
{ path: '/home', component: Home },
// :id 就是路由参数
// 匹配的哈希值为: /stu/1001 或 /stu/1002 或 /stu/abc
// 无法匹配的哈希值为: /stu 或 /stu/ 或 /stu/1001/ab
{ path: '/stu/:id', component: Stu },
// { path: '/stu/1001', component: Stu1 },
// { path: '/stu/1002', component: Stu2 },
]
})
const vm = new Vue({
el: '#app',
data: {
},
router
})
</script>
</body>
</html>
11、嵌套路由
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.user {
background-color: pink;
}
</style>
</head>
<body>
<div id="app">
<router-link to="/home">首页</router-link>
<router-link to="/user">用户管理</router-link>
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
<script>
const Home = {
template: `
<h1>这是 Home 组件</h1>
`
}
// 父组件:
const User = {
template: `
<div class="user">
<h2>用户中心</h2>
<router-link to="/user/profile">个人资料</router-link>
<router-link to="/user/posts">岗位</router-link>
<!-- 子路由展示在此处 -->
<router-view></router-view>
</div>
`
}
// 子组件:
const UserProfile = {
template: '<h3>个人资料:张三</h3>'
}
const UserPosts = {
template: '<h3>岗位:FE</h3>'
}
const router = new VueRouter({
routes: [
{
path: '/home',
component: Home
},
{
path: '/user',
component: User,
// 子路由配置:
children: [
{
// 当 /user/profile 匹配成功,
// UserProfile 会被渲染在 User 的 <router-view> 中
path: 'profile',
component: UserProfile
},
{
// 当 /user/posts 匹配成功
// UserPosts 会被渲染在 User 的 <router-view> 中
path: 'posts',
component: UserPosts
}
]
}
]
})
const vm = new Vue({
el: '#app',
data: {
},
router
})
</script>
</body>
</html>
12、路由高亮
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.user {
background-color: pink;
}
.router-link-exact-active,
.router-link-active {
color: green;
font-size: 40px;
}
</style>
</head>
<body>
<div id="app">
<router-link to="/home">首页</router-link>
<router-link to="/user">用户管理</router-link>
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
<script>
const Home = {
template: `
<h1>这是 Home 组件</h1>
`
}
// 父组件:
const User = {
template: `
<div class="user">
<h2>用户中心</h2>
<router-link to="/user/profile">个人资料</router-link>
<router-link to="/user/posts">岗位</router-link>
<!-- 子路由展示在此处 -->
<router-view></router-view>
</div>
`
}
// 子组件:
const UserProfile = {
template: '<h3>个人资料:张三</h3>'
}
const UserPosts = {
template: '<h3>岗位:FE</h3>'
}
const router = new VueRouter({
routes: [
{
path: '/home',
component: Home
},
{
path: '/user',
component: User,
// 子路由配置:
children: [
{
// 当 /user/profile 匹配成功,
// UserProfile 会被渲染在 User 的 <router-view> 中
path: 'profile',
component: UserProfile
},
{
// 当 /user/posts 匹配成功
// UserPosts 会被渲染在 User 的 <router-view> 中
path: 'posts',
component: UserPosts
}
]
}
],
// 修改默认高亮类名
linkActiveClass: 'itcast'
})
const vm = new Vue({
el: '#app',
data: {
},
router
})
</script>
</body>
</html>
13、路由高亮 - 两个类名的区别说明
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.user {
background-color: pink;
}
/*
.router-link-exact-active 精确匹配的类名
.router-link-active 模糊匹配的类名
比如:
当前的哈希值为:#/user/posts
对于 <a href="#/user" class="router-link-active">用户管理</a> 来说,因为 href=#/user 包含在 #/user/posts 中,因此,模糊匹配成功,那么当前的 a 就具有 模糊匹配的类名 router-link-active
对于 <a href="#/user/posts" class="router-link-exact-active router-link-active">岗位</a> 来说,因为 href 与 当前哈希值 是完全相同的
所以,不管是模糊还是精确 两个都匹配成功了,因此两个类名都有
*/
.router-link-exact-active,
.router-link-active {
color: green;
font-size: 40px;
}
</style>
</head>
<body>
<div id="app">
<router-link to="/home">首页</router-link>
<!-- 添加 exact 属性后,那么这个菜单的的高亮样式就变为精确匹配了,也就是说:只有 哈希值 与 当前to属性的值 完全相同的时候,才会给当前菜单添加高亮类名;如果仅仅是包含该to属性的值,那么,就不会再添加高亮类名了 -->
<router-link to="/user" exact>用户管理</router-link>
<router-view></router-view>
</div>
<script src="./vue.js"></script>
<script src="./vue-router.js"></script>
<script>
const Home = {
template: `
<h1>这是 Home 组件</h1>
`
}
// 父组件:
const User = {
template: `
<div class="user">
<h2>用户中心</h2>
<router-link to="/user/profile">个人资料</router-link>
<router-link to="/user/posts">岗位</router-link>
<!-- 子路由展示在此处 -->
<router-view></router-view>
</div>
`
}
// 子组件:
const UserProfile = {
template: '<h3>个人资料:张三</h3>'
}
const UserPosts = {
template: '<h3>岗位:FE</h3>'
}
const router = new VueRouter({
routes: [
{
path: '/home',
component: Home
},
{
path: '/user',
component: User,
// 子路由配置:
children: [
{
// 当 /user/profile 匹配成功,
// UserProfile 会被渲染在 User 的 <router-view> 中
path: 'profile',
component: UserProfile
},
{
// 当 /user/posts 匹配成功
// UserPosts 会被渲染在 User 的 <router-view> 中
path: 'posts',
component: UserPosts
}
]
}
],
// 修改默认高亮类名
// linkActiveClass: 'itcast'
})
const vm = new Vue({
el: '#app',
data: {
},
router
})
</script>
</body>
</html>
14、webpack的介绍
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
// webpack 是前端最流行的打包工具
// webpack 能做什么:
//
// 1 将 sass/less 等预编译的CSS语言 转化为 浏览器能够识别的 css 文件
// 2 能够将多个文件(比如:多个sass文件)打包生成一个文件
// 3 能够打包 images/styles/assets/scripts 等前端常见的文件
// 4 搭建了开发环境(开启了服务器)
// 5 监视文件变化,文件改变后,能够自动刷新浏览器
// 6 对于Vue来说,可以将 单文件组件(*.vue) 类型的文件,转化为浏览器能够识别的内容
// 项目打包上线:
// 1 只需要执行一条命令: npm run build 就可以对项目进行打包处理
// 2 所有文件(css/js/html) 的压缩合并
// 3 在打包的过程中 分离 或者 合并 文件
// 4 能够通过 代码分离 功能实现项目的按需加载
// 等等。。。
</script>
</body>
</html>
15、webpack-basic
main - 1 命令行使用方式
// webpack 的使用步骤:
// 1 安装: npm i -D webpack webpack-cli
// 2 webpack 使用的两种方式:
// 2.1 命令行的使用方式(知道)
// 2.2 配置文件
// webpack的四个核心概念:
// 1 入口 entry
// 2 出口 打包后输出内容
// 3 loaders 加载器:对于非JS的静态资源
// 4 plugins 插件
// 演示命令行的使用方式:
// webpack 入口文件 出口文件路径
// 最基本的打包: webpack ./src/main.js
// 注意:使用 webpack 的时候应该提供mode, 可以是: production 或者 development
// production 表示: 生产模式 -- 生产环境(也就是给用户使用的)
// development 表示: 开发模式 -- 开发环境(也就是给开发人员开发使用的)
// 指定模式: .\node_modules\.bin\webpack ./src/main.js --mode development
// 指定为生产模式: .\node_modules\.bin\webpack ./src/main.js --mode production
// 演示指定出口文件路径:
// .\node_modules\.bin\webpack ./src/main.js -o ./dist/a.js --mode production
const fn = () => {
console.log('main.js 中的fn 执行了')
}
fn()
main - 2 配置scripts去掉路径前缀
// .\node_modules\.bin\webpack ./src/main.js --mode development
// 解决问题: 去掉 .\node_modules\.bin\
// 1 在 package.json 的 scripts 中添加一个 build 脚本
// 2 将 webpack 命令作为 build 脚本的值
// 3 在终端中执行命令: npm run build 来运行上面创建好的脚本
const fn = () => {
console.log('main.js 中的fn 执行了')
}
fn()
main - 3 webpack打包处理的过程
// webpack打包处理的过程::
// 案例: 使用jQuery实现隔行变色的效果
// 浏览器或者NodeJS中 都无法直接识别 import 语法,
// 但是, 经过webpack打包处理后, 浏览器就能够识别这个语法了
// webpack打包处理的过程:
// 1 运行了webpack的打包命令: webpack ./src/main.js --mode development
// 2 webpack 就会找到我们指定的入口文件 main.js
// 3 webpack 就会分析 main.js 中的代码, 当遇到 import $ .... 语法的时候, 那么, webpack
// 就知道,我们要使用 jQuery 这个模块
// 4 webpack 就会将jQuery模块的代码拿过来
// 5 然后,继续往后分析, 如果在遇到 import 语法, 继续加载这个模块 ...
// 6 直到分析完成整个 JS 文件后, 将 main.js 中所有用到的模块代码 与 我们自己写的js代码
// 打包生成一个JS文件, 也就是 dist/main.js
// CommonJS 中的模块化语法
// const $ = require('jquery')
// ES6 中的模块化语法:
import $ from 'jquery'
$('#list > li:odd').css('background-color', 'red')
$('#list > li:even').css('background-color', 'green')
main - 4 webpack配置文件的使用
// webpack 配置文件的使用方式:
// 1 在项目根目录中创建配置文件: webpack.config.js
// ES6 中的模块化语法:
import $ from 'jquery'
$('#list > li:odd').css('background-color', 'pink')
$('#list > li:even').css('background-color', 'skyblue')
main - 5 webpack-dev-server的使用说明
// 开启服务器:
// webpack-dev-server
//
// 1 npm i -D webpack-dev-server
// 2 开启服务器
// 3 自动打开浏览器
// 4 监视文件变化, 自动刷新浏览器
// 5 等等
// 使用步骤:
// 1 安装: npm i -D webpack-dev-server
// 2 在 webpack.config.js 中配置 devServer 配置项
// 3 在 package.json 中添加一个配置项: "dev": "webpack-dev-server"
// webpack-dev-server 帮我们搭建了开发环境, 使用之后, 我们只需要
// 写代码完成功能即可, 其他的所有内容, 这个插件都帮我们处理了
// webpack-dev-server 命令 和 webpack 命令的区别:
// 开发期间 webpack-dev-server
// 项目打包上线 webpack
// webpack 命令会生产 dist 文件夹
// webpack-dev-server 不会创建 dist 文件夹, 而是将所有内容放在内存中
// ES6 中的模块化语法:
import $ from 'jquery'
$('#list > li:odd').css('background-color', '#def')
$('#list > li:even').css('background-color', 'skyblue')
main - 6 html-webpack-plugin的基本使用
// html-webpack-plugin
// 作用:
// 1 根据指定的模板页面(index.html)在内存中生产一个新的页面
// 并且, 浏览器打开的就是 生成的页面
// 2 能够自动引入 css/js 等文件
// 使用:
// 1 安装: npm i -D html-webpack-plugin
// 2 在 webpack.config.js 中导入这个模块
// 3 在 plugins 中配置
// ES6 中的模块化语法:
import $ from 'jquery'
$('#list > li:odd').css('background-color', '#def')
$('#list > li:even').css('background-color', 'skyblue')
main.js
// loader 加载器
// webpack 自身只能处理普通的JS文件, 而对于 非JS 文件, 都需要对应的 loader
// 来进行特殊的处理.
// 也就是每种类型的文件, 都有自己专门的loader来处理
// 比如:
// css文件,需要使用 style-loader css-loader
// less文件,需要使用 style-loader css-loader less-loader
// ...
// 使用步骤:
// 1 安装: npm i -D style-loader css-loader
// 2 在 webpack.config.js 中的 module 里面配置loader处理规则
// ES6 中的模块化语法:
import $ from 'jquery'
$('#list > li:odd').css('background-color', '#def')
$('#list > li:even').css('background-color', 'skyblue')
// 导入css文件
import './css/index.css'
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<!-- ul#list>li{这是第$个li元素}*10 -->
<ul id="list">
<li>这是第1个li元素</li>
<li>这是第2个li元素</li>
<li>这是第3个li元素</li>
<li>这是第4个li元素</li>
<li>这是第5个li元素</li>
<li>这是第6个li元素</li>
<li>这是第7个li元素</li>
<li>这是第8个li元素</li>
<li>这是第9个li元素</li>
<li>这是第10个li元素</li>
</ul>
<!-- <script src="./node_modules/jquery/dist/jquery.js"></script> -->
<!-- <script src="./src/main.js"></script> -->
<!-- <script src="./dist/main.js"></script> -->
<!-- <script src="./dist/bundle.js"></script> -->
<!-- 因为 webpack-dev-server 启动服务器之后,将输出文件直接放在当前服务器的根目录中了
所以,此处需要引入 /bundle.js 才能找到根目录中的 bundle 文件 -->
<!-- <script src="/bundle.js"></script> -->
</body>
</html>
webpack.config.js
// 注意: 不要使用 ES6 中的模块化语法 import/export
const path = require('path')
// const webpack = require('webpack')
// 导入html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
// 入口
entry: path.join(__dirname, './src/main.js'),
// 出口
output: {
path: path.join(__dirname, './dist'),
filename: 'bundle.js'
},
// 模式
mode: 'development',
devServer: {
// 自动打开浏览器
open: true,
// 修改端口号
port: 3000
// 热更新: 只将修改过得内容加载到页面中, 而不是刷新整个页面
// 第一步:
// hot: true
},
// 配置loader
module: {
rules: [
// test 是一个正则, 用来匹配加载文件的路径
// 比如: import './css/index.css'
// use 表示使用哪个loader来处理这个类型的文件
// 注意: 有顺序!!!
// 处理过程是: 从右往左
// css-loader 读取CSS文件,将其转化为一个模块
// style-loader 拿到css-loader读取到的css文件内容,然后,创建一个style标签,插入到head
{ test: /\.css$/, use: ['style-loader', 'css-loader'] }
]
},
plugins: [
// 第二步:
// new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
// 指定模板文件路径
template: path.join(__dirname, 'index.html')
})
]
}