Vue学习笔记(6)

本文深入解析Vue.js中的组件通信、属性绑定、路由参数及嵌套路由等核心概念,同时涵盖Vue Router的使用技巧,如重定向、路由高亮及参数传递。并通过实战案例,如开关灯组件通讯和SPA应用构建,帮助读者掌握Vue.js的高级特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值