Vue--2023.6.23

day1–2023.6.23

Vue--2023.6.23_第1张图片
Vue--2023.6.23_第2张图片

Vue--2023.6.23_第3张图片
Vue--2023.6.23_第4张图片

Vue快速上手

Vue 概念

Vue是一个用于构建用户界面的渐进式框架

构建用户界面:基于数据渲染出用户看到的页面
渐进式:循序渐进

Vue--2023.6.23_第5张图片

Vue的两种使用方式
  1. Vue 核心包开发
  • 场景:局部模块改造
  1. Vue 核心包 & Vue 插件工程化开发
  • 场景:整站开发
框架

一套完整的项目解决方案,提升开发效率(理解记忆规则)
规则一 官网

创建Vue 实例,初始化渲染

构建用户界面–>创建Vue实例 初始化渲染
步骤;

  1. 准备容器
  2. 引包(官网)–开发版本/生产版本
  3. 创建Vue实例 new Vue()
<script>
const app = new Vue({
	el:'#app',
	data:{
		 msg: 'He1lo黑马'
		 }
	 })
</script>
  1. 指定配置项–>渲染数据
    指定配置项 → 渲染数据
    ① el 指定挂载点
    ② data 提供数据
el:'#app'

插值表达式{{}}

插值表达式是一种Vue的模板语法

  1. 作用: 利用表达式进行插值,渲染到页面中
    表达式:是可以被求值的代码,JS引擎会将其计算出一个结果
  2. 语法: {{}}
    • 使用的数据要存在
    • 支持的是表达式,不是语句 if for
    • 不能在标签属性中使用 {{ }}
    <p:title="username"> </p>

Vue--2023.6.23_第6张图片

响应式特性

Vue核心特性:响应式
响应式:数据变化,视图自动更新
Vue--2023.6.23_第7张图片

响应式机制

Vue--2023.6.23_第8张图片
如何访问或修改数据呢?
data中的数据最终会被添加到实例上

开发者工具

安装Vue开发者工具:装插件调试Vue应用

  1. 通过谷歌应用商店安装 (国外网站)
  2. 极简插件:下载–>开发者模式–>拖拽安装–>插件详情允许访问文件

Vue--2023.6.23_第9张图片

Vue 指令

v-html / v-show /v-if / v-else / v-on / v-bind /v-for /v-model
Vue 会根据不同的指令,针对标签实现不同的功能
指令: 带有 v- 前缀的特殊 标签属性

v-html

作用: 设置元素的 innerHTML
语法: v-html="表达式

<div V-html="str"></div>

v-text不识别标签 v-html识别标签
Vue--2023.6.23_第10张图片

v-show vs v-if

v-show

1.作用控制元素显示隐藏
2.语法:V-show =“表达式” 表达式值 true 显示,false 隐藏
3.原理切换 display:none 控制显示隐藏
4.场景:频繁切换显示隐藏的场景

v-if

1.作用:控制元素显示隐藏(条件渲染)
2.语法:v-if =“表达式” 表达式值 true 显示false 隐藏
3.原理基于条件判断,是否 创建 或 除 元素节点
4.场景:要么显示,要么隐藏,不频繁切换的场景

v-else v-else-if
  1. 作用:辅助 v-if 进行判断渲染
  2. 语法: V-else v-else-if =“表达式”
  3. 注意需要紧挨着 v-if 一起使用

  <div id="app">
    <p v-if="gender === 1">性别:♂ 男</p>
    <p v-else>性别:♀ 女</p>
    <hr>
    <p v-if="score >=90">成绩评定A:奖励电脑一台</p>
    <p v-else-if="score >=70">成绩评定B:奖励周末郊游</p>
    <p v-else-if="score >=60">成绩评定C:奖励零食礼包</p>
    <p v-else>成绩评定D:惩罚一周不能玩手机</p>
  </div>

  <script src="./vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        gender: 1,
        score: 2
      }
    })
  </script>

Vue--2023.6.23_第11张图片

v-on

  1. 作用: 注册事件=添加监听+提供处理逻辑
  2. 语法:
    ①v-or:事件名=“内联语句”
    v-on:事件名=“method中的函数名”
<button v-on:click="fn">按钮</button>
  1. 简写:@事件名
<button @click="fn">按钮</button>
  1. 注意:method函数中的this指向vue实例

在这里插入图片描述

v-bind

  1. 作用: 动态的设置html的标签属性–>src url title href
  2. 语法: v-bind:属性名=“表达式”
  3. 注意:简写形式:属性名=“表达式”
<div id="app">
  <img  v-bind:src="url" alt="">
</div>

<script>
  const app=new Vue({
    el:'#app',
    data:{
      url:'./imgs/10-02.png'
    }
  })
</script>

图片切换案例-波仔学习之旅

Vue--2023.6.23_第12张图片

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <!-- <div id="app">
    <button v-show="index > 0" @click="index--">上一页</button>
    <div>
      <img :src="list[index]" alt="">
    </div>
    <button v-show="index < list.length - 1" @click="index++">下一页</button>
  </div>
  <script src="./vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        index: 0,
        list: [
          './imgs/11-00.gif',
          './imgs/11-01.gif',
          './imgs/11-02.gif',
          './imgs/11-03.gif',
          './imgs/11-04.png',
          './imgs/11-05.png',
        ]
      }
    })
  </script> -->

  <div id="app">
    <button v-show="index>0" @click="index--">上一页</button>
    <img :src="list[index]" alt="">
    <button v-show="index @click="index++">下一页</button>
  </div>
  <script src="./vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        index: 0,
        list: [
          './imgs/11-00.gif',
          './imgs/11-01.gif',
          './imgs/11-02.gif',
          './imgs/11-03.gif',
          './imgs/11-04.png',
          './imgs/11-05.png',
        ]
      }
    })
  </script>
</body>

</html>

v-for

  1. 作用:基于数据循环,多次渲染整个元素—> 数组,对象,数字
    Vue--2023.6.23_第13张图片

  2. 遍历数组语法
    v-for =“(item,index) in 数组”

    • item 每一项,index 下标
    • 数组省略index: v-for =“item in数组”

Vue--2023.6.23_第14张图片
Vue--2023.6.23_第15张图片
1.key 的值只能是字符串 或数字类型
2.key 的值必须具有 唯一性
3.推荐使用 id 作为 key (唯一) ,不推荐使用 index 作为 key (会变化,不对应)

v-model

  1. 作用:给表单元素使用,双向数据绑定—>可以快速获取或设置表单元素内容
    ①数据变化–>视图自动更新
    ②试图变化–>数据自动更新
  2. 语法:v-model=“变量”
<div id="app">
    <!-- 
      v-model 可以让数据和视图,形成双向数据绑定
      (1) 数据变化,视图自动更新
      (2) 视图变化,数据自动更新
      可以快速[获取][设置]表单元素的内容
     -->
    账户:<input type="text" v-model="username"> <br><br>
    密码:<input type="password" v-model="password"> <br><br>
    <button @click="login">登录</button>
    <button @click="reset">重置</button>
  </div>
<script src="./vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        username: '',
        password: ''
      },
      methods: {
        login() {
          console.log(this.username, this.password)
        },
        reset() {
          this.username = ''
          this.password = ''
        }
      }
    })
  </script>

综合案例-小黑记事本

列表渲染/删除功能/添加功能/底部统计/清空

Vue--2023.6.23_第16张图片

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <link rel="stylesheet" href="./css/index.css" />
  <title>记事本</title>
</head>

<body>

  <!-- 主体区域 -->
  <section id="app">
    <!-- 输入框 -->
    <header class="header">
      <h1>小黑记事本</h1>
      <input placeholder="请输入任务" class="new-todo" v-model="content" @keyup.enter="addItem" />
      <button class="add" @click="addItem">添加任务</button>
    </header>
    <!-- 列表区域 -->
    <section class="main">
      <ul class="todo-list">
        <li class="todo" v-for="(item, index) in list">
          <div class="view">
            <span class="index">{{index+1}}</span> <label>{{item.content}}</label>
            <button class="destroy" @click="delItem(item.id)"></button>
          </div>
        </li>
      </ul>
    </section>
    <!-- 统计和清空 -->
    <footer class="footer">
      <!-- 统计 -->
      <span class="todo-count">合 计:<strong> {{list.length}}</strong></span>
      <!-- 清空 -->
      <button class="clear-completed" @click="clear">
        清空任务
      </button>
    </footer>
  </section>

  <!-- 底部 -->
  <script src="../vue.js"></script>
  <script>
    // 1.渲染列表
    // 2. 删除某一项(给按钮添加一个点击事件 通过id传参)
    // 3. 添加任务(添加点击事件,双向数据绑定 ,构建对象 ,添加到list里面最前面)
    // 4. 底部合计
    // 5. 清空
    // 6. 回车添加任务
    const app = new Vue({
      el: '#app',
      data: {
        list: [
          {
            id: '123456',
            content: "游泳一小时"
          },
          {
            id: '223456',
            content: "跳舞一小时"
          },
        ],
        content: ' '
      },
      methods: {
        delItem(id) {
          // console.log(id)
          this.list = this.list.filter(item => item.id !== id)
        },
        addItem() {
          this.list.unshift({
            id: `${new Date().valueOf()}`,
            content: this.content
          }),
            this.content = ''


        },
        clear() {
          this.list = []
        }

      }

    })

  </script>
</body>

</html>

指令修饰符

通过“.”指明一些指令 后缀,不同的后缀封装了不同的处理操作 - 简化代码

  1. 按键修饰符
    @keyup.enter–>键盘回车监听
  2. v-model修饰符
    v-model.trim—>去除首尾空格
    v-model.number—>转数字
  3. 事件修饰符
    @事件名.stop—>阻止冒泡
    @事件名.prevent–>阻止默认行为
    Vue--2023.6.23_第17张图片

v-bind对于样式控制的增强-操作class

  1. 语法: class=“对象/数组”
  • ①对象—>键就是类名,值是布尔值.如果值为 true,有这个类,否则没有这个类
<div class="box":class="{类名1: 布尔值,类名2: 布尔值}"></div>

适用场景:一个类名,来回切换

  • ②数组一数组中所有的类,都会添加到盒子上,本质就是一个 class 列表
<div class="box":class="[ '类名1','类名2','类名3 ']"></div>

适用场景:批量添加或删除类

v-model 应用于其他表单元素

常见的表单元素都可以用 v-model 绑定关联一>快获取或设置表单元素的值
它会根据 控件类型自动选取正确的方法来更新元素
输入框 input:text value
文本域textarea value
复选框 input:checkbox checked
单选框input:radio checked
下拉菜单 select value

案例: 京东秒杀 tab 导航高亮

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    ul {
      display: flex;
      border-bottom: 2px solid #e01222;
      padding: 0 10px;
    }

    li {
      width: 100px;
      height: 50px;
      line-height: 50px;
      list-style: none;
      text-align: center;
    }

    li a {
      display: block;
      text-decoration: none;
      font-weight: bold;
      color: #333333;
    }

    li a.active {
      background-color: #e01222;
      color: #fff;
    }
  </style>
</head>

<body>

  <div id="app">
    <ul>
      <li v-for="(item,index) in list" :key="item.id" @click="activeIndex=index">
        <a href="#" :class="{active:index===activeIndex}">{{item.name}}</a>
      </li>

    </ul>
  </div>
  <script src="../vue.js"></script>
  <script>
    // 1. 删除ul中所有的li,是用数据来渲染li
    // 2. 在data中声明一个 默认选中的索引 0
    // 3. 判断li在循环的时候 索引是0 1 2 哪个索引和data中声明的一样
    // 4. 一样就添加active高亮
    const app = new Vue({
      el: '#app',
      data: {
        activeIndex: 0,//记录高亮
        list: [
          { id: 1, name: '京东秒杀' },
          { id: 2, name: '每日特价' },
          { id: 3, name: '品类秒杀' }
        ]

      }
    })
  </script>
</body>

</html>

计算属性

  1. 概念:基于现有的数据,计算出来的新属性.依赖的数据变化,自动重新计算。
  2. 语法:
  • ①声明在 computed 配置项中,一个计算属性对应一个函数
  • ②使用起来和普通属性一样使用 {{计算属性名}}
    Vue--2023.6.23_第18张图片

computed 计算属性 vs methods 方法

  • computed计算属性
  1. 作用:封装了一段对于数据的处理,求得一个结果
  2. 语法:
    ①写在 computed 配置项中
    ②作为属性,直接使用–>this.计算属性 或者 {{ 计算属性 }}

区别:
缓存特性(提升性能):
计算属性会对计算出来的结果缓存,再次使用直接读取缓存
依赖项变化了,会自动重新计算一并再次缓存

  • methods方法
  1. 作用:给实例提供一个方法,调用以处理业务逻辑
  2. 语法:
    ① 写在 methods 配置项中
    ② 作为方法,需要调用–> this.方法名() 或者 {{ 方法名() }} 或者 @事件名=“方法名”

计算属性完整写法

计算属性默认的简写,只能读取访问,不能“修改
如果要“修改"一>需要写计算属性的完整写法

  • 简写
computed:{
	计算属性名(){
		一段代码逻辑(计算逻辑)
		return 结果
	}
}
  • 完整写法
computed:{
	计算属性名:{
		get(){
			一段代码逻辑(计算逻辑)
			return 结果
			},
		set(修改的值) {
			  一段代码逻辑(修改逻辑)
				 }
			}
       }

成绩案例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="./styles/index.css" />
    <title>Document</title>
  </head>
  <body>
    <div id="app" class="score-case">
      <div class="table">
        <table>
          <thead>
            <tr>
              <th>编号</th>
              <th>科目</th>
              <th>成绩</th>
              <th>操作</th>
            </tr>
          </thead>

          <tbody v-if="list.length > 0">
            <tr v-for="(item, index) in list" :key="item.id">
              <td>{{ index + 1 }}</td>
              <td>{{ item.subject }}</td>
              <!-- 需求:不及格的标红, < 60, 加上 red 类 -->
              <td :class="{ red: item.score < 60 }">{{ item.score }}</td>
              <td><a href="#">删除</a></td>
            </tr>
          </tbody>

          <tbody v-else>
            <tr>
              <td colspan="5">
                <span class="none">暂无数据</span>
              </td>
            </tr>
          </tbody>

          <tfoot>
            <tr>
              <td colspan="5">
                <span>总分:246</span>
                <span style="margin-left: 50px">平均分:79</span>
              </td>
            </tr>
          </tfoot>
        </table>
      </div>
      <div class="form">
        <div class="form-item">
          <div class="label">科目:</div>
          <div class="input">
            <input
              type="text"
              placeholder="请输入科目"
            />
          </div>
        </div>
        <div class="form-item">
          <div class="label">分数:</div>
          <div class="input">
            <input
              type="text"
              placeholder="请输入分数"
            />
          </div>
        </div>
        <div class="form-item">
          <div class="label"></div>
          <div class="input">
            <button class="submit" >添加</button>
          </div>
        </div>
      </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>

    <script>
      const app = new Vue({
        el: '#app',
        data: {
          list: [
            { id: 1, subject: '语文', score: 62 },
            { id: 7, subject: '数学', score: 39 },
            { id: 12, subject: '英语', score: 70 },
          ],
          subject: '',
          score: ''
        }
      })
    </script>
  </body>
</html>

watch侦听器(监视器)

  1. 作用:监事数据变化,执行一些 业务逻辑 或 异步操作
  • 异步操作:ajax,setInterval等
  1. 应用场景
  • 翻译器
    Vue--2023.6.23_第19张图片
  1. 语法
  • 简单写法–>简单类型数据,直接监视
data:{
 words:'苹果',
 obj:{
 	words:'苹果'
 	}
 },
  watch:{
// 该方法会在数据变化时,触发执行
数据属性名 (newValue,oldValue){
	一些业务逻辑 或 异步操作.
},
'对象.属性名' (newValue,oldValue){
	一些业务逻辑 或 异步操作.
}
}
  • 完整写法–>添加额外配置项
    ①deep:true 对复杂数据类型深度监视
    ②immediate:true 初始化立刻执行一次handler方法
    Vue--2023.6.23_第20张图片
data:{
 words:'苹果',
 obj:{
 	words:'苹果',
 	lang:'italy'
 	},
 },
  watch:{//watch完整写法
数据属性名:{
	deep: true// 深度监听
	immediate:true// 默认先执行一次 不管数据变没变
	handler(newVal) {
		console.log(newValue)
		}
	}
}
  1. 面试题 请说明一下计算属性和侦听器的区别
    ①计算属性有缓存特性,侦听器没有
    ②侦听器可以有操作异步,计算属性不能有
    ③意义: 计算腐性是不能写在 data中,新属性依赖于多个值的变化,侦听器侦听的属性必须要写在data中,data中的属性变化了侦听器中的结果就要发生变化
    ④计算属性可以从依赖到结果(get),结果到依赖(set)侦听器只能是属性变化引发数据变化

生命周期

Vue生命周期和生命周期的四个阶段

什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来)

Vue生命周期:一个Vue实例从创建到销毁的整个过程
  • new Vue()—>销毁
    生命周期四个阶段:① 创建 ②挂载 ③ 更新 ④ 销毁
  • ①创建阶段:响应式数据
data:{
	title:'计数器',
	count:100
	}
  • ② 挂载阶段:渲染模板
<div id="app">
	<h3>{{ title }}</h3>
	<div>
		<button>-</button>
		<span>{{ count }}</span>
		<button>+</button>
	</div>
</div>
  • ③ 更新阶段: 修改数据,更新视图
    Vue--2023.6.23_第21张图片

  • ④ 销毁阶段: 销毁实例
    Vue--2023.6.23_第22张图片

Vue生命周期钩子函数

Vue生命周期过程中,会自动运行一些函数,被称为生命周期钩子, 让开发者可以在特定阶段运行自己的代码

Vue--2023.6.23_第23张图片

Vue--2023.6.23_第24张图片

Vue 生命周期钩子案例 - 新闻列表 & 输入自动聚焦

Vue--2023.6.23_第25张图片

报错 401 未授权

在这里插入图片描述

小黑记账清单

Vue--2023.6.23_第26张图片
Vue--2023.6.23_第27张图片

工程化开发

  1. 核心包传统开发模式:基于 html/css /js 文件,直接引入核心包,开发Vue。
  2. 工程化开发模式:基于构建工具 (例如: webpack)的环境中开发 Vue。
    Vue--2023.6.23_第28张图片

工程化开发 & 脚手架 Vue CLI

  1. 基本介绍
    Vue CLI 是 Vue 官方提供的一个全局命令工具
    可以帮助我们快速创建一个开发 Vue 项目的标准化基础架子。(集成了 webpack 配置)
    Vue--2023.6.23_第29张图片

Vue--2023.6.23_第30张图片

  1. 使用步骤
  • 全局安装(一次): yarn global add @vue/cli或 npm i @vue/cli -g
    Vue--2023.6.23_第31张图片

  • 查看 Vue 版本: vue --version
    在这里插入图片描述

  • 创建项目架子: vue create project-name(项目名-不能用中文)

项目路径 C:\Users\Administrator\study-dmj
Vue--2023.6.23_第32张图片

Vue--2023.6.23_第33张图片

  • 启动项目: yarn serve 或 npm run serve (找package.json)
    Vue--2023.6.23_第34张图片
    访问成功
    在这里插入图片描述

项目运行流程

C:\Users\Administrator\study-dmj

Vue--2023.6.23_第35张图片
Vue--2023.6.23_第36张图片

命令yarn serve
命令npm run serve --> main.js
Vue--2023.6.23_第37张图片
Vue--2023.6.23_第38张图片

组件化 & 根组件

  1. 组件化:一个页面可以拆成一个个组件,每个组件有着自己独立的结构、样式、行为
  2. 好处:便于维护,利于复用一>提升开发效率
  3. 组件分类:普通组件、根组件。
  4. 根组件:整个应用最上层的组件,包裹所有普通小组件
  • 根组件
    Vue--2023.6.23_第39张图片

  • 组件树

Vue--2023.6.23_第40张图片

App.vue 文件 (单文件组件) 的三个组成部分:结构,行为,样式
  1. 语法高亮插件
    Vue--2023.6.23_第41张图片
  2. 三部分组成: template script style
    Vue--2023.6.23_第42张图片

Vue--2023.6.23_第43张图片

普通组件的注册使用

必须要引入
Vue--2023.6.23_第44张图片

  1. 组件注册的两种方式(在哪使用就必须在那引入并注册)
    1. 局部注册:只能在注册的组件内使用
    • ①创建.vue 文件(单文件组件)
    • ②使用的组件内导入,并局部注册components:{ 组件名:组件对象 }
import AABb from "路径" //导入
components:{AABb}//注册
<AaBb></AaBb>//使用

Vue--2023.6.23_第45张图片

    1. 全局注册:所有组件内都能使用
    • ① 创建vue文件(单文件组件)
    • ② 在main.js 中引入 , 并全局注册 Vue.component(组件名,组件对象)(只注册一次,哪里都能用 后面就不用注册 不用引入)
//1.创建一个AaBb.vue
//2.注册
import AaBb from"路径”//引入
Vue.component("AaBb",AaBb)//注册
//3使用
//随便在哪里都可以使用 还是使用标签的形式使用

Vue--2023.6.23_第46张图片

  1. 注意:组件名规范大驼峰命名法,如: HmHeade
  2. 技巧:一般都用局部注册,如果发现确实是通用组件再抽离到全局

小兔鲜

20203.6.27 day4

组件的三大组成部分(结构/样式/逻辑)

Vue--2023.6.23_第47张图片

组件的样式冲突 scoped

默认情况:写在组件中的样式会全局生效因此很容易造成多个组件之间的样式冲突问题

  1. 全局样式默认组件中的样式会作用到全局
  2. 局部样式: 可以给组件加上 scoped 属性可以让样式只作用于当前组件
<style scoped>
</style>
scoped原理
  1. 当前组件内标签都被添加 data-v-hash值的属性
  2. css选择器都被添加 [data-v-hash值] 的属性选择器
  3. 最终效果: 必须是当前组件的元素,才会有这个自定义属性,才会被这个样式作用到

Vue--2023.6.23_第48张图片

data是一个函数

  • 一个组件的 data 选项必须是一个函数。保证每个组件实例,维护独立的一份数据对象
  • 每次创建新的组件实例,都会新执行一次 data 函数,得到一个新对象。

Vue--2023.6.23_第49张图片

Vue--2023.6.23_第50张图片

组件通信

  1. 什么是组件通信
    组件通信,就是指 组件与组件 之间的数据传递
    • 组件的数据是独立的,无法直接访问其他组件的数据。
    • 想用其他组件的数据一>组件通信
      Vue--2023.6.23_第51张图片

不同的组件关系 和 组件通信方案分类

  1. 组件关系分类
    • 子关系
    • 非父子关系
      Vue--2023.6.23_第52张图片
  2. 组件通信解决方案
  • 父子关系
props 和 $emit

Vue--2023.6.23_第53张图片

  • 非父子关系
1. provide&inject
2. eventbus

Vue--2023.6.23_第54张图片

  • 通用解决方案: Vuex (适合复杂业务场景)
父—>子通信流程

Vue--2023.6.23_第55张图片

  1. 父组件通过 props 将数据传递给子组件
  2. 流程
  • 在父组件中准备数据
 data() {
    return {
      msg:["1,2"]
    }
  }
  • 在父组建中使用子组件,通过属性把父组件中的数据传递给子组件(key value方式)
<template>
  <div id="app">
    <Son :notice="msg"></Son>
  </div>
</template>

  • 在子组件中通过props来接收父组件传来的数据
<script>
export default {
  props: ['notice']
}
</script>
  • 在组件中渲染使用
<template>
<div class="son">{{ notice }}</div>
</template>

Vue--2023.6.23_第56张图片

子—>父通信流程
  1. 子组件利用 $emit 通知父组件修改更新
  2. 过程
  • 在子组件中调用 $emit(父组件中自定义事件名,实参)
<script>
export default {
  props: ['notice'],
  methods: {
    handlerFix() {
      // this.$emit("自定义事件名",传给自定义事件对应的参数)
        this.$emit("fatherEvent","中午吃什么,到黑马")
      }
    }
}
</script>
  • 在父组件中子组件标签上写自定义事件名=”处理函数“
<template>
  <div id="app">
    <Son :notice="msg" @fatherEvent="handlerFather"></Son>
  </div>
</template>

  • 在处理函数中写业务逻辑,接受参数
<script>
import Son from './components/Son.vue'
export default {
  methods: {
    handlerFather(num) {
      this.msg = num
      console.log("父组件的事件触发了",num);
    }
  }
}
</script>

Vue--2023.6.23_第57张图片

非父子通信(拓展)-event bus事件总线
  1. 作用: 非父子之间,进行简易消息传递(复杂场景–>Vuex)
    Vue--2023.6.23_第58张图片
  • 创建一个都能访问到的事件总线(空 Vue 实例)–>utils/EventBus.js
    Vue--2023.6.23_第59张图片

  • A组件(接收方),监听 Bus 实例的事件
    Vue--2023.6.23_第60张图片

  • B组件(发送方) 触发Bus 实例的事件
    在这里插入图片描述

什么是prop

  1. prop定义: 组件上注册的一些自定义属性
  2. prop作用:向子组件传递数据
    Vue--2023.6.23_第61张图片

prop校验

  1. 思考:组件的 prop 可以乱传么?
  • 作用:为组件的 prop 指定验证要求,不符合要求,控制台就会有警告提示—>帮助开发者,快速发现错误
  1. 语法
  • 类型校验

    数组传参写法(不是校验)

 props: ["username", "age", "isSingle", "car", "hobby"],

对象写法简单校验


//props:{
	//	校验的属性名:类型 // Number String Boolean...
	//	}

props: {
    username: String,
    age: Number,
    isSingle: Boolean,
    car: Object,
    hobby: Array
  }

对象写法完整校验

//props: {
//	校验的属性名: {
//	type: 类型, // Number String Boolean
//	required: true,// 是否必填
//	default: 默认值,// 默认值
//	validator (value) {
	// 自定义校验逻辑
//		return 是否通过校验
//		}
//	}
//}


props: {
	hobby: {
	type: Array ,// Number String Boolean
	required: true,// 是否必填
	default: '小黑',// 默认值
	validator :function (value) {
	// 自定义校验逻辑
    let res = value.includes('篮球')
     return res
		}
	}
}
  • 非空校验
required: true,// 是否必填
  • 默认值
	default: 默认值,// 默认值
  • 自定义校验
validator :function (value) {
	// 自定义校验逻辑
    let res = value.includes('篮球')
     return res
		}

props & data、单向数据流

  1. 共同点:都可以给组件提供数据
  2. 区别:
  • data 的数据是自己的一>随便改
  • props 的数据是外部的一> 不能直接改,要遵循 单向数据流 (通知父组件修改)
  1. 单向数据流:父级 props 的数据更新,会向下流动,影响子组件。这个数据流动是单向的

Vue--2023.6.23_第62张图片
口诀: 谁的数据谁负责

综合案例:小黑记事本(组件版)

需求说明:

  1. 拆分基础组件
  2. 渲染待办任务
  3. 添加任务
    • 在输入框中输入内容v-model
    • 在点击添加任务按钮的时候
      • this.$emit(父组件中的自定义事件名,数据)
      • 在父组件的子组件标签上定义自定义事件名+函数
      • 在函数中写逻辑–> 通知父组件将子组件传来的
    • 加工成需要的对象形式 添加到todoList中
  4. 删除任务
    • 给删除按钮绑定点击事件 传id
    • 实现点击事件的事件处理函数
    • 在事件处理函数通过this.$emit id
    • 在父组件的子组件标签上 声明自定义事件
    • 在处理函数中写逻辑(删除逻辑 --id flter)
  5. 底部合计 和 清空功能
  6. 持久化存储
    Vue--2023.6.23_第63张图片

2023.6.28-day5

进阶语法

v-model原理

  1. 原理: v-model本质上是一个语法糖。例如应用在输入框上,就是 value属性 和 input事件 的合写
  2. 作用:实现数据的双向绑定
  • ①数据变,视图跟着变 :value
  • ②视图变,数据跟着变 @input
    Vue--2023.6.23_第64张图片

表单类组件封装 & v-model 简化代码

Vue--2023.6.23_第65张图片

  1. 表单类组件 封装
  • ①父传子:数据应该是组件 props 传递过来的,拆解 v-model 绑定数据
  • ② 子传父:监听输入,子传父传值给父组件修改
    Vue--2023.6.23_第66张图片
  1. 父组件v-model简化代码,实现子组件和组件数据双向绑定
  • ①子组件中: props 通过 value 接收,事件触发 input
  • ②父组件中: v-model 给组件直接绑数据

Vue--2023.6.23_第67张图片

.sync修饰符

  1. 作用:可以实现 子组件 与组件数据的双向定,简化代码
  2. 特点: prop属性名,可以自定义,非固定为 value
  3. 场景:封装弹框类的基础组件, visible属性 true显示 false隐藏
  4. 本质: 就是 :属性名 和 @update:属性名 合写

Vue--2023.6.23_第68张图片

ref和$refs

  1. 作用:利用 ref和$refs 可以用于 获取 dom 元素或组件实例
  2. 特点: 查找范围–>当前组件内(更精确稳定)
  • ①获取dom:

      - ① 1.1 目标标签--添加ref属性
    
<BaseForm ref="baseForm"></BaseForm>
	- ① 1.2 恰当时机 , 通过this.$refs.xxx, 获取目标组件,就可以调用组件对象里面的方法
this.$refs.baseForm.组件方法()

Vue异步更新 , $nextTick

  1. 点击编辑,显示编辑框

  2. 让编辑框,立刻获取焦点
    Vue--2023.6.23_第69张图片

  3. 问题:“显示之后”,立刻获取焦点是不能成功的!
    原因: Vue 是异步更新 DOM (提升性能)

  4. $nextTick:等 DOM 更新后,才会触发执行此方法里的函数体

  • 语法:this.$nextTick()
this.$nextTick(()=>(
	this.$refs.inputRef.focus()//获取焦点
})

内置指令 自定义指令

Vue--2023.6.23_第70张图片

自定义指令

  1. 定义 : 自己定义的指令,可以封装一些 dom 操作,扩展额外功能
  2. 需求:当页面加载时,让元素将获得焦点
    • autofocus 在 safari 浏览器有兼容性
    • 操作dom: dom元素.focus() --> 麻烦
mounted(){
	this.$refs .inp.focus()
	}
  1. 全局注册—语法
    在inserted 钩子函数中,配置指令dom逻辑
 Vue.directive( '指令名'{
 	"inserted" (el) {
 	// 可以对 el 标签,扩展额外功能
 	el.focus()
 	}
 })
  • v-focus
Vue.directive("focus", {
  inserted(el) {
    console.log(el)
    el.focus()
  }
})
  • v-color
Vue.directive("color", {
  inserted(el, binding) {
    el.style.color = binding.value
  }
})
  1. 局部注册–语法 (基本不用)
    Vue--2023.6.23_第71张图片

  2. 标签上 v指令名使用Vue--2023.6.23_第72张图片

自定义指令 v-color

  1. 需求:实现一个 color 指令 - 传入不同的颜色,给标签设置文字颜色
  2. 语法:在绑定指令时,可以通过“等号”的形式为指令绑定具体的参数值
    ①v-指令名 ="指令值”,通过 等号可以绑定指令的值
    ②通过binding.value 可以拿到指令的值
    ③通过 update 钩子,可以监听指令值的变化,进行dom更新操作

在这里插入图片描述

  • 通过 binding.value 可以拿到指令值,指令值修改会 触发 update 函数。
    Vue--2023.6.23_第73张图片

  • v-color

Vue.directive("color", {
  inserted(el, binding) {
    el.style.color = binding.value
  }
})

自定义指令 v-loading 指令封装

  1. 场景:实际开发过程中,发送请求需要时间,在请求的数据未回来时,页面会处于空白状态 =>用户体验不好
  2. 分析
      1. 本质loading 效果就是一个蒙层,盖在了盒子上
      1. 数据请求中,开启loading状态,添加蒙层
      1. 数据请求完毕,关闭loading状态,移除蒙层
  3. 实现
      1. 准备一个loading 类,通过伪元素定位,设置宽高,实现蒙层
      1. 开启关闭loading 状态(添加移除蒙层),本质只需要添加移除类即可
      1. 结合自定义指令的语法进行封装复用

2023.6.29–day6

非父子通信–event bus 事件总线

  1. 作用:非父子组件之间,进行简易消息传递。(复杂场景一 Vuex)

  2. 创建一个都能访问到的事件总线(空Vue实例)–>utils/EventBus.js
    在这里插入图片描述

  3. A组件(接收方),监听 Bus 实例的事件
    Vue--2023.6.23_第74张图片

  4. B组件(发送方),触发 Bus 实例的事件
    在这里插入图片描述

Vue--2023.6.23_第75张图片

非父子通信(拓展) - provide & inject

  1. provide & inject 作用: 跨层级共享数据
  2. 父组件 provide 提供数据

Vue--2023.6.23_第76张图片

  1. 子/孙组件inject 取值使用

Vue--2023.6.23_第77张图片
Vue--2023.6.23_第78张图片

插槽

  1. 当组件内某一部分结构不确定,想要自定义怎么办?
  • 用插槽slot占位封装
  1. 插槽使用的基本步骤?
  • 先在组件内用slot占位
  • 使用组件时,传入具体标签内容插入

默认插槽

先在组件内用slot占位
使用组件时,传入具体标签内容插入

  1. 作用 : 让组件内部的一些结构支持自定义
  2. 组件内需要定制的结构部分,改用占位
  3. 使用组件时,标签内部,传入结构替换slot
    Vue--2023.6.23_第79张图片

后备内容

  1. 定义:通过插槽完成了内容的定制,传什么显示什么,但是如果不传,则显示默认
  2. 在标签内写好后备内容
<template>
  <div class="dialog">
    <div class="dialog-content">
    
      <slot> 默认后备内容</slot>
      
    </div>
  </div>
</template>
  1. 当使用组件并未给我们传入具体标签或内容时,后备内容会显示
    Vue--2023.6.23_第80张图片

具名插槽

  1. 需求:组件内有多处不确定的结构怎么办

  2. 语法

  • 多个slot使用name属性区分名字

Vue--2023.6.23_第81张图片

  • template配合v-slot:名字来分发对应标签

Vue--2023.6.23_第82张图片

  • v-slot:插槽名可以简写为 #插槽名

作用域插槽–传参

  1. 作用域插槽: 可以给插槽上绑定数据,供将来使用组件时使用
  2. 步骤
  • 给 slot 标签以添加属性的方式传值
    LinTable.vue
<slot :id="item.id"> </slot>

在这里插入图片描述

  • 所有添加的属性,都会被收集到一个对象中
    App.vue
    在这里插入图片描述

  • 在template中,通过#插槽名="obj”接收,默认插槽名为 defaultVue--2023.6.23_第83张图片

综合案例-商品列表

  1. 分离结构变成组件 ---->LinTable
  • 在components里面创建了一个LinTable.vue
  • 把App.vue中的关于 Table的html和样式拿过去
  • 在App.vue中引入使用
  1. 父子组件通信,把表格用数据渲染出来

  2. 分离结构,把my-tag部分分离成组件

  3. myTag的开发

  • 让输入和tag内容只能显示一个
    - 在 LinTag中添加一个状态 isEdit: false
    - 使用v-if 和else 决定显示和隐藏
  • 双击div让输入框显示
    - 给div添加双击事件
    - 在事件处理函数中isEdit为true
  • 当输入框显示的时候 让输入框自动聚焦
    - 获取input元素
    - 使用$nextTick()让输入框自动聚焦
  • 当输入框失去焦点的时候,隐藏输入框
    - 给输入框添加blur让isEdit=true
  1. 回显tag内容 :value
  2. 按回车 改变 tag的值(v-model原理底层是input输入框)
  • 给input 绑定keyup.enter事件
  • 获取输入框中改变后的值
  • this.$emit(“父组件中的自定义事件”,传输入框的值)
  • 使用v-model简化 :value="item.tag"和 @input=“事件处理函数”

路由入门

  1. 路由的介绍
  • 生活中的路由: 设备和ip的对应关系

Vue--2023.6.23_第84张图片
根据路由就能知道不同路径的,应该匹配渲染哪个组件
Vue--2023.6.23_第85张图片

单页应用程序: SPA - Single Page Application

  1. 单页面应用(SPA):所有功能在一个htm页面上实现
  2. 具体示例: 网易云音乐 https://music.163.com/
  3. 优缺点:
  • 优点:按需更新性能高,开发效率高,用户体验好
  • 缺点:学习成本,首屏加载慢,不利于SEO
  1. 单页面应用场景: 系统类网站/内部网站/文档网站/移动端站点
  2. 单页面应用程序,之所以开发效率高,性能高,用户体验好最大的原因就是:页面按需更新
  3. 要按需更新,首先就需要明确:访问路径和组件的对应关系!
  4. 访问路径和组件的对应关系如何确定呢?
  • 路由

多页面应用程序:MPA - Multiple Page Application

  1. 有多个html组成的应用
  2. 区别
    Vue--2023.6.23_第86张图片
    3.多页面应用场景: 公司官网/电商类网站

路由概念

  1. 生活中的路由: 设备和ip的对应关系
  2. 概念:路径和组件的关系

VueRouter 的基本使用

  1. 作用:修改地址栏路径时,切换显示匹配的组件
    路径改变,对应组件切换

  2. 说明: Vue 官方的一个路由插件,是一个第三方包(需要下载)

  3. 官网: https://v3.router.vuejs.org/zh/

Vue--2023.6.23_第87张图片

VueRouter 的 使用(5 + 2)
5个基础步骤(固定)
  1. 下载:下载 VueRouter 模块到当前工程,版本3.6.5
yarn add vue-router@3.6.5
npm i vue-router@3
  1. 引入
import VueRouter from 'vue-router'
  1. 安装注册
Vue.use(VueRouter)
  1. 创建路由对象
const router = new VueRouter()
  1. 注入,将路由对象注入到new Vue实例中,建立关联
new Vue({
	render: h => h(App),
router
}).$mount('#app')
2个核心步骤
  1. 创建需要的组件(views目录),配置路由规则
    components页面中的某一块是一个组件
    views:整个页面是一个组件
  • Find.vue
  • My.vue
  • Friend.vue
//绝对路径:@指代src目录,可以用于快速引入组件
import Find from '@/views/Find.vue'
import My from './views/My .vue'
import Friend from './views/Friend.vue'
const router = new VueRouter({
	routes: [
		{ path:'/find', component: Find },
		{ path:'/my', component: My },
		{ path:'/friend', component: Friend },
	]
})

  1. 配置导航,配置路由出口(路径匹配的组件 router-view 显示的位置)
<div class="footer_wrap">
	<a href="#/find">发现音乐</a>
	<a href="#/my">我的音乐</a>
	<a href="#/friend">朋友</a>
</div>
<div class="top">
	<router-view></router-view>
</div>

组件目录存放问题

页面组件放在vue.js中
复用组件放在components里面

路由进阶

路由模块封装

路由模块化

  1. 将main.js里面路由的相关配置抽离出来,在根目录准备router文件夹,新建一个index声明式导航-导航链接

url:localhost:8080/#/find

声明式导航 & 导航高亮

需求:实现导航高亮效果

  1. vue-router 提供了一个全局组件 router-link (取代 a 标签)能跳转,配置 to 属性指定路径(必须)。
  2. 本质还是 a 标签,to 无需#/能高亮,默认就会提供高亮类名,可以直接设置高亮样式
  3. vue-router提供的全局组件,用于替换 a 标签

  4. - 必须传入to属性,指定路由路径值
  5. 能跳转,能高亮(自带激活时的类名)
//书写: 
<router-link to="/find">发现音乐</router-link>
//解析:
 <a href="#/find"class="router-link-active router-link-exact-active"> </a>

Vue--2023.6.23_第88张图片

  1. 注意点: router-link必须具备to属性,等同于a标签必须具备href,不需要加#,仍然被解析成了a标签
 <!-- <a href="#/find">发现音乐</a>
      <a href="#/my">我的音乐</a>
      <a href="#/friend">朋友</a>                 -->

      <!-- 声明式导航 - 导航链接 -->
      <!-- 注意点: router-link必须具备to属性,等同于a标签必须具备href,不需要加#,仍然被解析成了a标签 -->
      <!-- 导航高亮 加类名 class="router-link-exact-active router-link-active" -->
      <router-link to="/find">发现音乐</router-link>
      <router-link to="/my">我的音乐</router-link>
      <router-link to="/friend">朋友</router-link>
  1. 导航高亮 加类名 class=“router-link-exact-active router-link-active”

精确匹配&模糊匹配

有模糊匹配一定有精准匹配

  1. 精准匹配router-link-exact-active
    • 包含关系不高亮
  2. 模糊匹配router-link-active
    • 包括包含关系 也能命中
    • http://localhost:3007/#/friend和http://localhost:3007/#/friend/index.html都能命中
    • 应用: 一级导航,二级导航都能高亮
  3. 啥时候出现router-link-active:模糊匹配通过的时候就会添加这个类名
  4. 啥时候出现router-link-exact-active: 精准匹配通过才会出现这个类名

自定义高亮类名

 linkActiveClass: 'active',
 linkExactActiveClass: 'exact-active'

Vue--2023.6.23_第89张图片

Vue--2023.6.23_第90张图片

Vue路由—重定向

  1. 配置重定向后默认打开不会是空白页
  2. 路由关系映射表中添加规则
routes: [
    // 配置重定向(路由表的前面) redirect强制跳转到对应的地址
    { path: '/', redirect: '/home' },
    //path重定向前的路径(无法显示页面的路径),redirect需要显示页面的路径
    ]

Vue--2023.6.23_第91张图片

路由404

Vue--2023.6.23_第92张图片

  1. 作用: 当路径找不到匹配时,给个提示页面
  2. 位置:配在路由最后
  3. 语法: path:“*” (任意路径)-前面不匹配就命中最后这个

Vue--2023.6.23_第93张图片

路由模式

  1. 问题: 路由的路径看起来不自然,有#,能否切成真正路径形式?
  • hash路由(默认)例如: http://localhost:8080/#/home
  • history路由(常用) 例如: http://localhost:8080/home (以后上线需要服务器端支持)
//index.js
const router = new VueRouter({
  mode: "history"//路由模式
  // 路由模式的原理
  // hash:vue内部会有一个hashChange监听事件来监听hash值得变化
  // history:原生API-->popStage监听URLChange的事件
})

声明式导航传参(查询参数传参 &动态路由传参


导航传参

  1. 声明式导航传参
  • 1.1 查询参数传参(ur1? 后面直接跟k1=v1&k2=v2)
    语法格式如下:
    • ①跳转: to=“/path?key=v1”
    • ②接收: 对应页面组件接收传递过来的值:$route.query.key

Vue--2023.6.23_第94张图片

  • 1.2 动态路由传参

    • ①配置动态路由–>/search/:key
      Vue--2023.6.23_第95张图片

    • ②配置导航链接(跳转): to=“/search/黑马程序员”

    • ③对应页面组件接收传递过来的值(接受): $route.params.参数名
      Vue--2023.6.23_第96张图片

问号传的query接,冒号传的params接

  1. 编程式导航传参

编程式导航(重点)

问题:点击按钮跳转如何实现?
编程式导航:用JS代码来进行跳转
两种语法:
①path 路径跳转
②name 命名路由跳转

编程式导航传参(查询参数传参 &态路由传参

  • 1 编程式导航–path跳转
  • 2.1.1查询参数传参
    • 2.1.1.1第一种跳转方式(不传参)
      this.$router.push(‘路径’)
      传递参数->path路径后面通过?传递
      传参方式1: 单参数,固定值
 //传参方式1: 单参数,固定值
 this.$router.push('/search?key=123')
  • 2.1.1.2第二种跳转方式(传参)
    this.$router.push({
    path:‘路径’
    })

    传参方式2:完整写法

//传参方式2:等同于简单写法的传参(不推荐)
	this.$router.push({
			path:'/search?key=456'
	})

Vue--2023.6.23_第97张图片
传参(推荐path搭配query)

// 传参方式3:多参数,变量值
this.$router.push({
			path:'./search',
			query:{
			key:123,
			val:this.num
			}
	})

  1. 2编程式导航–name跳转
    ①在路由规则中添加name属性

    this.$router.push({
    name:‘路由的name’
    })
//index.js
{ name: 'searchPage',path:'/search/:word?',component:Search },

在这里插入图片描述
Vue--2023.6.23_第98张图片
传参(推荐name搭配params)

 //传值方式4(动态路由参数)
this.$router.push({
			name:'searchPage',
			params:{
			key:123
			}
	})

查询参数怎么传?问号传的query接,query传的query接
动态参数怎么传?冒号传的params接,params传的params接推荐的两种方式:1. path搭配query 2.name搭配params

$route 和 $router 的区别

  1. $route 当前路由信息对象 -> 提供路由信息
  2. $router 全局路由对象 ->提供路由方法

综合案例:面经基础版

分析:配路由 + 实现功能

  1. 配路由
  • 首页 和 面经详情,两个一级路由
  • 首页内四个可切换页面(嵌套二级路由)
  1. 实现功能
  • 首页请求染
  • 跳转传参 到 详情页,详情页渲染
  • 组件缓存,优化性能

Vue--2023.6.23_第99张图片

一级路由

二级路由

导航高亮

请求渲染

路由传参

缓存组件

keep-alive

<keep-alive>//包裹路由出口, 
	<router-view></router-view>
</keep-alive>

你可能感兴趣的:(vue.js,javascript,前端)