VUE学习笔记(黑马2023版 持更)

VUE学习笔记(黑马2023版)

  • 第一天
    • 1.Vue是什么?
    • 2.创建一个Vue实例
      • 2.1.准备容器(Vue所管理的范围)
      • 2.2.引包(开发版本包/生产版本包)
      • 2.3.创建实例
      • 2.4.指定配置项 el data
    • 3.插值表达式
      • 3.1.作用:
      • 3.2.语法:
      • 3.3.注意点
      • 3.4.实践案例
    • 4.Vue响应式特性
      • 4.1.什么是响应式?
      • 4.2.访问和修改数据
    • 5.Vue开发者工具安装:装插件调试Vue应用
      • 5.1浏览器为谷歌的安装方法
        • 通过极简插件安装
      • 5.2浏览器为Edge的安装方法
    • 6.Vue指令
      • 6.1 v-html
      • 6.2 v-show 和 v-if
        • 6.2.1 v-show
        • 6.2.2v-if
        • 6.2.3案例实践
      • 6.3 v-else和v-else-if
      • 6.4v-on
      • 6.5v-bind
      • 图片切换案例-波仔学习之旅
      • 6.6v-for
      • 图书管理案例-小黑的书架
      • 6.7 v-for中的key
      • 6.8 v-model
      • 综合案例-小黑记事本
        • 功能需求:
        • 代码实现:
  • 第二天
    • 7.指令修饰符
      • 7.1按键修饰符
      • 7.2 v-model修饰符
      • 7.3 事件修饰符
    • 8. v-bind对于样式控制的增强 - 操作class
    • 案例:京东秒杀tab导航高亮
    • 9.v-bind对于样式控制的增强 - 操作style
    • 10.v-model应用于其他表单元素
    • 11.计算属性
      • 11.1computed计算属性 vs methods方法
      • 11.2 计算属性完整写法
    • 综合案例 - 成绩案例
    • 12.watch侦听器(监视器)
    • 综合案例 - 水果购物车
  • 第三天
    • 13.Vue生命周期和生命周期的四个阶段
    • 综合案例-小黑记账清单
    • 14. 工程化开发和脚手架Vue CLI
      • 开发Vue的两种方式:
      • 脚手架的基本介绍
      • 安装教程:(前置条件需要node环境)
      • 创建项目和启动项目
    • 15.组件化开发和根组件
      • App.vue文件(单文件组成的三个组成部分)
    • 16.普通组件的注册使用
      • 组件注册的两种方式:
      • 使用:
      • 局部注册使用范例:

第一天

第一天准备文件:
链接:https://pan.baidu.com/s/14Cd_aMQMsgMTZi72AefZ1g?pwd=6666
提取码:6666

1.Vue是什么?

Vue是一个用于构建用户界面渐进式框架
1.构建用户界面:基于数据动态渲染页面
2.渐进式:循序渐进的学习
3.框架:一套完整的项目解决方案,提升开发效率

2.创建一个Vue实例

创建Vue实例,初始化渲染

2.1.准备容器(Vue所管理的范围)

比如:

<div id="app">

<div>

2.2.引包(开发版本包/生产版本包)

前往官网下载包
进入官网后依次点击起步
VUE学习笔记(黑马2023版 持更)_第1张图片
点击安装

VUE学习笔记(黑马2023版 持更)_第2张图片
在安装时选择开发版本,因为开发版本包含完整的警告和调试模式
VUE学习笔记(黑马2023版 持更)_第3张图片
如果不想安装,可以用用一下语句直接导入
VUE学习笔记(黑马2023版 持更)_第4张图片

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>

2.3.创建实例

<script>
//一旦引入VueJS核心包,在全局环境,就有了Vue构造函数
    const app = new Vue()
script>

2.4.指定配置项 el data

el指定挂载点,选择器指定控制的是哪个盒子
data提供数据
比如在第三步的基础上:

<script>
    const app = new Vue({
        el:'#app',
        data:{
            msg:'Hello 黑马'
        }
    })
script>

上述代码指控制id为app的盒子,数据为‘Hello 黑马’
再将第一步的div盒子更改为:

<div id="app">
    {{msg}}
div>

最后在网页中运行的效果为:
VUE学习笔记(黑马2023版 持更)_第5张图片
完整代码如下:

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>
<body>
    
<div id="app">
    {{msg}}
div>


<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>

<script>
    const app = new Vue({
        el:'#app',
        data:{
            msg:'Hello 黑马'
        }
    })
script>

body>
html>

3.插值表达式

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

3.1.作用:

利用表达式进行插值,渲染到页面中
表达式:是可以被求值的代码,JS引擎会将其计算出一个结果

3.2.语法:

{{ 表达式 }}
比如:

<div id="app">
    {{msg}}
div>

3.3.注意点

(1)使用的数据必须存在,要事先声明
(2)支持的是表达式,而不是语句,比如:if for…
例如以下是错误的:

<p>
    {{ if }}
p>

(3)不能再标签属性中使用{{ }}插值
例如以下是错误的:

<p title="{{ username }}">
p>

3.4.实践案例

实践案例如下:

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>
<body>
    

<div id="app">
    <p>{{ nickname }}p>
    <p>{{ nickname.toUpperCase() }}p>
    <p>{{ nickname + '你好' }}p>
    <p>{{ age>=18 ? '成年' : '未成年' }}p>
    <p>{{ friend.name }}p>
div>


<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>

<script>
    const app = new Vue({
        el:'#app',
        data:{
            nickname: 'tony',
            age: 18,
            friend: {
                name: 'jepson',
                desc: '热爱学习'
            }
        }
    })
script>

body>
html>

效果图如下:
VUE学习笔记(黑马2023版 持更)_第6张图片

4.Vue响应式特性

4.1.什么是响应式?

数据改变,视图自动更新

4.2.访问和修改数据

访问数据:“实例.属性名”
例如:在上一个案例实践的网页中,按f12进入控制台输入一下代码,成功访问数据
VUE学习笔记(黑马2023版 持更)_第7张图片
修改数据:“实例.属性名”=“值”
例如:在上一个案例实践的网页中,按f12进入控制台输入一下代码,成功修改数据
VUE学习笔记(黑马2023版 持更)_第8张图片

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

5.1浏览器为谷歌的安装方法

通过极简插件安装

1.点击链接打开极简网址
2.搜索Vue
3.安装Vue Devtools
VUE学习笔记(黑马2023版 持更)_第9张图片
4.点击推荐下载
5.下载完成后解压
6.打开管理扩展程序
VUE学习笔记(黑马2023版 持更)_第10张图片
7.将刚下载解压好的后缀为.crx的程序拖拽到下图所示页面的空白部分中
VUE学习笔记(黑马2023版 持更)_第11张图片
8.弹出提示框,点击添加扩展程序
9.安装完成后点击插件详情
VUE学习笔记(黑马2023版 持更)_第12张图片
10.将允许访问文件网址打开
在这里插入图片描述
11.重启浏览器(一定要重启,不是刷新),插件生效
VUE学习笔记(黑马2023版 持更)_第13张图片

5.2浏览器为Edge的安装方法

1.如图点击扩展
VUE学习笔记(黑马2023版 持更)_第14张图片
2.在弹出的窗口中选择“打开Microsoft Edge加载项”
3.在新窗口中搜索vue
4.安装Vue.js devtools
VUE学习笔记(黑马2023版 持更)_第15张图片
5.安装完成后,点击管理扩展
VUE学习笔记(黑马2023版 持更)_第16张图片
6.点击Vue.js devtools的“详细信息”,将“允许访问文件URL”打上勾
在这里插入图片描述
7.重启浏览器(一定要重启,不是刷新),插件生效
VUE学习笔记(黑马2023版 持更)_第17张图片

6.Vue指令

Vue会根据不同的指令,针对标签实现不同的功能
指令:带有v-前缀的特殊标签属性

6.1 v-html

  • 作用:设置元素的innerHTML
  • 语法:v-html=“表达式”
	<div v-html="表达式">div>
  • 案例实践:
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>
<body>
    
<div id="app">
    <div v-html="msg">div>
div>


<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>

<script>
    const app = new Vue({
        el:'#app',
        data:{
            msg:`
                黑马程序员
                `//注意``是模版字符串,不要省略
        }
    })
script>

body>
html>

效果展示:
VUE学习笔记(黑马2023版 持更)_第18张图片

6.2 v-show 和 v-if

6.2.1 v-show
  • 作用:控制元素显示隐藏
  • 语法:v-show=“表达式” 表达式值true显示,false隐藏
  • 原理:切换display:none控制显示隐藏
  • 适用场景:频繁切换显示隐藏的场景
6.2.2v-if
  • 作用:控制元素显示隐藏(条件渲染
  • 语法:v-if=“表达式” 表达式值true显示,false隐藏
  • 原理:基于条件判断,是否创建移除元素节点
  • 使用场景:要么显示,要么隐藏,不频繁切换的场景
6.2.3案例实践
DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Documenttitle>
   <style>
       .box{
           height: 50px;
           width: 100px;
           border-radius: 5px;
           text-align: center;
           border: solid 3px;
           padding: 10px;
           margin: 10px;
       }
   style>
head>
<body>
   
   <div id="app">
       <div v-show="flag" class="box">我是v-show控制的盒子div>
       <div v-if="flag" class="box">我是v-if控制的盒子div>
   div>
   
   <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>

<script>
   const app = new Vue({
       el:'#app',
       data:{
           flag:true
       }
   })
script>
   

body>
html>
flag:true//当flag元素为true时,id为app的控件显示

效果如图:

VUE学习笔记(黑马2023版 持更)_第19张图片

flag:false//当flag元素为false时,id为app的控件不显示

效果如图:
VUE学习笔记(黑马2023版 持更)_第20张图片

6.3 v-else和v-else-if

  • 作用:辅助v-if进行判断渲染
  • 语法:
    v-else
    v-else-if=“表达式”
<p v-if="表达式">我是一个p标签p>
<p v-else-if="表达式">我是一个p标签p>
<p v-else>我是一个p标签p>
  • 注意:需要紧挨v-if使用
  • 案例实践
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>
<body>
    <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="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>

    <script>
        const app = new Vue({
            el:'#app',
            data:{
                gender: 2,
                score: 80
            }
        })
    script>

body>
html>

案例结果如下:
VUE学习笔记(黑马2023版 持更)_第21张图片

6.4v-on

  • 作用:注册事件=添加监听+提供处理逻辑
  • 语法:
    ①v-on:事件名=“内联语句”
    例如:
<button v-on:click="count--">我是一个按钮button>

②v-on:事件名=“methods中的函数名”
例如:

<button v-on:click="fn">我是一个按钮button>
  • 简写:@事件名

<button @click="fn">我是一个按钮button>
  • 案例实践
    ①v-on:事件名="内联语句"的案例
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>
<body>
    
<div id="app">
    
    <button v-on:click="count--">-button>
    <span>{{ count }}span>
    
    <button @click="count++">+button>
div>


<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>

<script>
    const app = new Vue({
        el:'#app',
        data:{
            count: 100
        }
    })
script>

body>
html>

案例结果如下:
VUE学习笔记(黑马2023版 持更)_第22张图片

②v-on:事件名="methods中的函数名"的案例

DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>
<body>
    
<div id="app">
    
    <button @click="fn">切换显示隐藏button>
    <h1 v-show="isshow">黑马程序员h1>
div>


<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>

<script>
    const app2 = new Vue({
        el:'#app',
        data:{
            isshow: true
        },
        methods:{
            fn(){
                //此处的语句可以替换为app2.isshow = !app2.isshow,但鼓励下面的做法,更利于代码的维护
                this.isshow = !this.isshow
            }
        }
    })
script>

body>
html>

案例结果如下:
VUE学习笔记(黑马2023版 持更)_第23张图片
VUE学习笔记(黑马2023版 持更)_第24张图片

  • v-on参数传递
    • 语句
<button @click="fn(参数一,参数二)">
	按钮
button>
const app= new Vue({
	el:#app,
	methods:{
		fn (a, b) {
			console.log('这是一个fn函数')
		}
	}
})
  • 参数传递案例实践
    案例说明:通过点击对应的饮品,实现银行卡余额减少对应价钱
    代码如下:
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>Documenttitle>
  <style>
    .box {
      border: 3px solid #000000;
      border-radius: 10px;
      padding: 20px;
      margin: 20px;
      width: 200px;
    }
    h3 {
      margin: 10px 0 20px 0;
    }
    p {
      margin: 20px;
    }
  style>
head>
<body>

  <div id="app">
    <div class="box">
      <h3>小黑自动售货机h3>
      <button @click="buy(5)">可乐5元button>
      <button @click="buy(10)">咖啡10元button>
      <button @click="buy(8)">牛奶8元button>
    div>
    <p>银行卡余额:{{ money }}元p>
  div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        money: 100
      },
      methods: {
        buy (price) {
          this.money -= price
        }
      }
    })
  script>
body>
html>

部分案例效果图如下:
VUE学习笔记(黑马2023版 持更)_第25张图片

6.5v-bind

  • 作用:动态的设置html的标签属性(src url title…)
  • 语法:v-bind:属性名=“表达式”
<img v-bind:属性名="表达式">
  • 简写::属性名=“表达式”
<img :属性名="表达式">
  • 案例实践
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>
<body>
    
<div id="app">
    <img v-bind:src="imgUrl" v-bind:title="msg" alt="">
    
    <img :src="imgUrl" :title="msg" alt="">
div>


<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>

<script>
    const app = new Vue({
        el:'#app',
        data:{
            imgUrl:'./imgs/10-01.png',
            msg:'hello 波仔'
        }
    })
script>

body>
html>

案例结果如下:
VUE学习笔记(黑马2023版 持更)_第26张图片

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

  • 核心思路分析:
    1.数组存储图片路径
    2.准备下标index,数组[下标]
  • 案例代码如下:
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>Documenttitle>
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="https://cdn.jsdelivr.net/npm/vue@2/dist/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>

案例部分效果如下:
VUE学习笔记(黑马2023版 持更)_第27张图片
VUE学习笔记(黑马2023版 持更)_第28张图片

6.6v-for

  • 作用:基于数据循环,多次渲染整个元素
  • 遍历数组语法:
    v-for=“(item,index) in 数组
    item:每一项
    index:下标
<li v-for="(item,index) in list">我是一个li标签li>
  • 省略index
    v-for = “item in 数组”
<li v-for="item in list">我是一个li标签li>
  • 案例实践
DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
head>
<body>
    
<div id="app">
    <h3>小黑水果店h3>
    <ul>
        <li v-for="(item,index) in list">{{ item }} - {{ index }}li>
    ul>
    
    <ul>
        
        <li v-for="item in list">{{ item }}li>
    ul>
div>


<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>

<script>
    const app = new Vue({
        el:'#app',
        data:{
            list:['西瓜','苹果','鸭梨']
        }
    })
script>

body>
html>

案例结果如下:
VUE学习笔记(黑马2023版 持更)_第29张图片

图书管理案例-小黑的书架

  • 案例说明:
    实现下图页面,并按删除按钮后,实现对应项的删除
    VUE学习笔记(黑马2023版 持更)_第30张图片
  • 核心思路分析:
    ①通过v-for遍历数组
    ②给删除按钮绑上@click,实现点击后删除的功能
  • 实现代码
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>Documenttitle>
head>
<body>

  <div id="app">
    <h3>小黑的书架h3>
    <ul>
      <li v-for="(item,index) in booksList" :key="item.id">
        <span>{{ item.name }}span>
        <span>{{ item.author }}span>
        
        <button @click="del(item.id)">删除button>
      li>
    ul>
  div>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js">script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        booksList: [
          { id: 1, name: '《红楼梦》', author: '曹雪芹' },
          { id: 2, name: '《西游记》', author: '吴承恩' },
          { id: 3, name: '《水浒传》', author: '施耐庵' },
          { id: 4, name: '《三国演义》', author: '罗贯中' }
        ]
      },
      methods:{
        del ( id ) {
          //通过id进行删除数组中的对应项
          //filter(不会改变原数组):根据条件,保留满足条件的对应项,得到一个新数组
          this.booksList=this.booksList.filter(item => item.id != id)

        }
      }
    })
  script>
body>
html>

6.7 v-for中的key

  • 作用:给列表项添加的唯一标识。便于Vue进行列表项的正确排序复用
  • 语法:
    key属性=“唯一标识”
<li v-for="(item,index) in 数组" :key="唯一值">
  • 注意点:
    ①key的值只能是字符串数字类型
    ②key的值必须具有唯一性
    ③推荐使用id作为key(唯一),不推荐使用index作为key(会变化,不对应)

6.8 v-model

  • 作用:
    表单元素使用,双向数据绑定 -> 可以快速获取或设置表单元素内容
    ①数据变化 -> 视图自动更新
    视图变化 -> 数据自动更新
  • 语法:v-model=‘变量’
<input type="text" v-model="变量">
  • 案例实践
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>Documenttitle>
head>
<body>

  <div id="app">
    
    账户:<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="https://cdn.jsdelivr.net/npm/[email protected]/dist/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>
body>
html>

综合案例-小黑记事本

功能需求:

1.列表渲染
v-for key的设置,{{}}插值表达式
2.删除功能
①v-on调用传参
②filter过滤,覆盖原数组
3.添加功能
①通过v-model绑定输入框 -> 实时获取表单元素的内容
②点击按钮,进行新增,往数组最前面加unshift
4.底部统计和清空
①数组.length累计长度
②覆盖数组清空列表
③v-show控制隐藏
VUE学习笔记(黑马2023版 持更)_第31张图片

代码实现:
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 v-model="todoName" placeholder="请输入任务" class="new-todo" />
    <button @click="add" class="add">添加任务button>
  header>
  
  <section class="main">
    <ul class="todo-list">
      <li class="todo" v-for="(item,index) in list" :key="item.id">
        <div class="view">
          <span class="index">{{ index + 1 }}span> <label>{{ item.name }}label>
          <button @click="del(item.id)" class="destroy">button>
        div>
      li>
    ul>
  section>
  
  
  <footer class="footer" v-show="list.length > 0">
    
    <span class="todo-count">合 计:<strong> {{list.length}}strong>span>
    
    <button @click="clear" class="clear-completed">
      清空任务
    button>
  footer>
section>


<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
<script>

  const app = new Vue({
    el: '#app',
    data: {
      todoName:'',
      list:[
        {id: 1, name: '跑步一公里'},
        {id: 2, name: '跳绳200次'},
        {id: 3, name: '游泳100米'}
      ]      
    },
    methods:{
      del(id){
        this.list = this.list.filter( item =>item.id !== id)
      },
      add(){
        //trim()去除空格
        if(this.todoName.trim() === ''){
          alert('请输入任务名称')
          return
        }
        //unshift()增加到数组的最前面
        this.list.unshift({
          id: +new Date(),//用时间戳临时作为id
          name:this.todoName,
        })
        this.todoName=''
      },
      clear(){
        this.list=[]
      }
    }
  })

script>
body>
html>

第二天

第二天准备文件:
链接:https://pan.baidu.com/s/1_3NUO6dKECpi7OmV5VMSzg?pwd=6666
提取码:6666

7.指令修饰符

通过"."指明一些指令后缀,不同后缀封装了不同的处理操作

7.1按键修饰符

@keyup.enter 用于键盘回车监听(较为常用)
例如:


<input @keyup.enter="add" v-model="todoName"/>

7.2 v-model修饰符

  • v-model.trim去除首尾空格(较为常用)
    例如:
    <input v-model.trim="username" type="text"><br>
  • v-model.number转数字(较为常用)
    例如:
    <input v-model.number="age" type="text"><br>

7.3 事件修饰符

  • @事件名.stop阻止冒泡

    <div @click="alert('老父亲被点击了')" class="father">
      <div @click.stop="alert('儿子被点击了')" class="son">儿子div>
    div>
  • @事件名.prevent阻止默认行为
<a @click.prevent="notLink" href="http://www.baidu.com">阻止默认行为a>

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

语法:
:class=“对象/数组”

对象->键就是类名,值是布尔值。如果值为true,有这个类,否则没有这个类
适用场景:一个类名,来回切换

<div class="box" :class="{ 类名1: 布尔值, 类名2: 布尔值 }">div>

数组->数组中所有的类,都会添加到盒子上,本质就是一个class列表
适用场景:批量添加或删除类

<div class="box" :class="[类名1, 类名2 ,类名3 ]">div>

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

  • 案例说明:点击不同的链接,实现点击的链接高亮功能
    在这里插入图片描述
  • 核心思路:
    1.基于数据动态渲染tab(v-for实现)
    2.准备下标记录高亮的是哪一个tab
    3.基于下标,动态控制class类名(v-bind:class)
  • 案例实现:
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>Documenttitle>
  <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 :class="{ active: index===activeIndex }" href="#">{{item.name}}a>li>
    ul>
  div>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        activeIndex: 0, //存储选中的下标
        list: [
          { id: 1, name: '京东秒杀' },
          { id: 2, name: '每日特价' },
          { id: 3, name: '品类秒杀' }
        ]

      }
    })
  script>
body>
html>

9.v-bind对于样式控制的增强 - 操作style

  • 语法:
    :style=“样式对象”
<div class="box" :style="{ CSS属性名1: CSS属性, CSS属性名2: CSS属性}">div>
  • 适用场景:某个具体属性的动态设置
  • 实践案例
    实现进度条的控制,如图所示
    VUE学习笔记(黑马2023版 持更)_第32张图片

代码如下:

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>Documenttitle>
  <style>
    .progress {
      height: 25px;
      width: 400px;
      border-radius: 15px;
      background-color: #272425;
      border: 3px solid #272425;
      box-sizing: border-box;
      margin-bottom: 30px;
    }
    .inner {
      width: 50%;
      height: 20px;
      border-radius: 10px;
      text-align: right;
      position: relative;
      background-color: #409eff;
      background-size: 20px 20px;
      box-sizing: border-box;
      transition: all 1s;
    }
    .inner span {
      position: absolute;
      right: -20px;
      bottom: -25px;
    }
  style>
head>
<body>
  <div id="app">
    <div class="progress">
      <div class="inner" :style="{width: percent + '%'}">
        <span>{{percent + '%'}}span>
      div>
    div>
    <button @click="percent=25">设置25%button>
    <button @click="percent=50">设置50%button>
    <button @click="percent=75">设置75%button>
    <button @click="percent=100">设置100%button>
  div>
  <script src="./vue.js">script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        percent: 30
      }
    })
  script>
body>
html>

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

常见的表单元素都可以用v-model绑定关联 -> 快速获取设置表单元素的值
他会根据控件类型自动选取正确的方法来更新元素

  • 输入框 input:text -> value
  • 文本域 textarea -> value
  • 复选框 input:checkbox -> checked
  • 单选框 input:radio -> checked
  • 下拉菜单 select -> value

案例实践如下:

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>Documenttitle>
  <style>
    textarea {
      display: block;
      width: 240px;
      height: 100px;
      margin: 10px 0;
    }
  style>
head>
<body>

  <div id="app">
    <h3>小黑学习网h3>

    姓名:
      <input type="text" v-model="username"> 
      <br><br>

    是否单身:
      <input type="checkbox" v-model="isSingle"> 
      <br><br>

    
    性别: 
      <input v-model="gender" type="radio" name="gender" value="1"><input v-model="gender" type="radio" name="gender" value="2"><br><br>

    
    所在城市:
      <select v-model="cityId">
        <option value="101">北京option>
        <option value="102">上海option>
        <option value="103">成都option>
        <option value="104">南京option>
      select>
      <br><br>

    自我描述:
      <textarea v-model="desc">textarea> 

    <button>立即注册button>
  div>
  <script src="./vue.js">script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        username:'',
        isSingle:false,
        gender:"",
        cityId:'101',
        desc:""
      }
    })
  script>
body>
html>

11.计算属性

  • 概念:基于现有的数据,计算出来的新属性。因爱的数据变化,自动计算
  • 语法:
  • ①声明在computed配置项中,一个计算属性对应一个函数
  • ②使用起来和普通属性一样使用{{ 计算属性名 }}
computed: {
	计算属性名(){
		基于现有数据,编写求值逻辑
		return 结果
	}
}

案例实践

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>Documenttitle>
  <style>
    table {
      border: 1px solid #000;
      text-align: center;
      width: 240px;
    }
    th,td {
      border: 1px solid #000;
    }
    h3 {
      position: relative;
    }
  style>
head>
<body>

  <div id="app">
    <h3>小黑的礼物清单h3>
    <table>
      <tr>
        <th>名字th>
        <th>数量th>
      tr>
      <tr v-for="(item, index) in list" :key="item.id">
        <td>{{ item.name }}td>
        <td>{{ item.num }}个td>
      tr>
    table>

    
    <p>礼物总数:{{ totalCount }} 个p>
  div>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js">script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        // 现有的数据
        list: [
          { id: 1, name: '篮球', num: 1 },
          { id: 2, name: '玩具', num: 2 },
          { id: 3, name: '铅笔', num: 5 },
        ]
      },
      computed:{
        //注意是属性不是函数
        totalCount(){
          //0表示求和起始值,reduce遍历list,将每个item的值加上后返回给sum
          let total= this.list.reduce((sum, item) => sum + item.num, 0)
          return total
        }
      }
    })
  script>
body>
html>

案例效果展示:
VUE学习笔记(黑马2023版 持更)_第33张图片

11.1computed计算属性 vs methods方法

  • computed计算属性
    作用:封装了一段对于数据的处理,求得一个结果
    缓存特性:计算属性会对计算出来的结果缓存,再次使用直接读取缓存,依赖项变化了,会自动重新计算 -> 并再次缓存
  • methods方法:
    作用:给实例提供一个方法,调用以处理业务逻辑

11.2 计算属性完整写法

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

computed: {
	计算属性名(){
		一段代码逻辑(计算逻辑)
		return 结果
	}
}

完整写法:

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

综合案例 - 成绩案例

  • 案例说明:
    制作一个成绩表,有编号,科目,成绩属性,并且有删除,添加,和求总分,平均分的功能
    VUE学习笔记(黑马2023版 持更)_第34张图片- 需求说明
  1. 渲染功能
    v-if v-else:用来判断呈现表格的形式
    v-for:遍历数组
    v-bind:设置不及格的高亮
  2. 删除功能
    点击传参,filter过滤覆盖原数组
    .prevent阻止默认行为
  3. 添加功能
    v-model(.trim ,number)绑定数据
    unshift修改数组更新视图
  4. 统计总分,求平均分
  • 代码实现:
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>Documenttitle>
  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>
              
              <td :class="{ red: item.score < 60 }">{{item.score}}td>
              <td><a @click.prevent="del(item.id)" href="www.baidu.com">删除a>td>
            tr>
            
          tbody>

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

          <tfoot>
            <tr>
              <td colspan="5">
                <span>总分:{{ totalScore }}span>
                <span style="margin-left: 50px">平均分:{{ averageScore }}span>
              td>
            tr>
          tfoot>
        table>
      div>
      <div class="form">
        <div class="form-item">
          <div class="label">科目:div>
          <div class="input">
            <input
              type="text"
              placeholder="请输入科目"
              v-model.trim="subject"
            />
          div>
        div>
        <div class="form-item">
          <div class="label">分数:div>
          <div class="input">
            <input
              type="text"
              placeholder="请输入分数"
              v-model.number="score"
            />
          div>
        div>
        <div class="form-item">
          <div class="label">div>
          <div class="input">
            <button @click="add" 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: 20 },
            { id: 7, subject: '数学', score: 99 },
            { id: 12, subject: '英语', score: 70 },
          ],
          subject: '',
          score: ''
        },
        methods: {
          del(id){
            //filter():筛选,根据id判断筛选内容是否符合条件,若不等则返回给list
            this.list = this.list.filter(item => item.id !== id)
          },
          add(){
            if(!this.subject){
              alert("请输入科目")
              return
            }
            if(typeof this.score !== 'number'){
              alert("请输出正确的成绩")
              return
            }
            //往前面加unshift,往后面加push
            this.list.unshift({
              id: +new Date(),
              subject: this.subject,
              score: this.score
            })
            this.subject=''
            this.score=''
          }
        },
        computed:{
          totalScore(){
            return this.list.reduce((sum, item) => sum+item.score , 0)
          },
          averageScore(){
            if(this.list.length === 0){
              return 0
            }
            //计算属性可以直接使用,toFixed(2)保留两位小数
            return (this.totalScore / this.list.length).toFixed(2)
          }
        }
      })
    script>
  body>
html>

12.watch侦听器(监视器)

  • 作用:监听数据变化,执行一些业务逻辑或异步操作
  • 语法:
  1. 简单写法:
    简单类型数据,直接监视
data:{
	words:'苹果',
	obj:{
		words:'苹果'
	}
},

watch: {
	数据属性名(newValue, oldValue) {
		一些业务逻辑 或 异步操作
	},
	'对象.属性名'(newValue, oldValue) {
		一些业务逻辑 或 异步操作
	}
	
}

案例:
需求:输入内容,实时翻译
VUE学习笔记(黑马2023版 持更)_第35张图片
代码实现:

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>Documenttitle>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
        font-size: 18px;
      }
      #app {
        padding: 10px 20px;
      }
      .query {
        margin: 10px 0;
      }
      .box {
        display: flex;
      }
      textarea {
        width: 300px;
        height: 160px;
        font-size: 18px;
        border: 1px solid #dedede;
        outline: none;
        resize: none;
        padding: 10px;
      }
      textarea:hover {
        border: 1px solid #1589f5;
      }
      .transbox {
        width: 300px;
        height: 160px;
        background-color: #f0f0f0;
        padding: 10px;
        border: none;
      }
      .tip-box {
        width: 300px;
        height: 25px;
        line-height: 25px;
        display: flex;
      }
      .tip-box span {
        flex: 1;
        text-align: center;
      }
      .query span {
        font-size: 18px;
      }

      .input-wrap {
        position: relative;
      }
      .input-wrap span {
        position: absolute;
        right: 15px;
        bottom: 15px;
        font-size: 12px;
      }
      .input-wrap i {
        font-size: 20px;
        font-style: normal;
      }
    style>
  head>
  <body>
    <div id="app">
      
      <div class="query">
        <span>翻译成的语言:span>
        <select>
          <option value="italy">意大利option>
          <option value="english">英语option>
          <option value="german">德语option>
        select>
      div>

      
      <div class="box">
        <div class="input-wrap">
          <textarea v-model="obj.words">textarea>
          <span><i>⌨️i>文档翻译span>
        div>
        <div class="output-wrap">
          <div class="transbox">{{ result }}div>
        div>
      div>
    div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js">script>
    <script>
      // 接口地址:https://applet-base-api-t.itheima.net/api/translate
      // 请求方式:get
      // 请求参数:
      // (1)words:需要被翻译的文本(必传)
      // (2)lang: 需要被翻译成的语言(可选)默认值-意大利
      // -----------------------------------------------
      
      const app = new Vue({
        el: '#app',
        data: {
          // words: ''
          obj: {
            words: ''
          },

          result:'',//翻译结果
          timer: null
        },
        // 具体讲解:(1) watch语法 (2) 具体业务实现
        watch: {
          // 该方法会在数据变化时调用执行
          // newValue新值, oldValue老值(一般不用)
          // words (newValue) {
          //   console.log('变化了', newValue)
          // }

           'obj.words' (newValue) {
            //console.log('变化了', newValue)
            //防抖:延迟执行 -> 干啥事先等一等,延迟一会,一段时间内没有再次触发,才执行
            clearTimeout(this.timer)
            this.timer = setTimeout(async () => {
              //这里是ajax的内容
              const res = await axios({
              url: 'https://applet-base-api-t.itheima.net/api/translate',
              params:{
                words:newValue
              }
            })
            this.result = res.data.data 
            console.log(res.data.data)
            }, 300)
          }
        }
      })
    script>
  body>
html>

  1. 完整写法
    添加额外配置项
    (1)deep:true 对复杂类型深度监视
    (2)immediate:true 初始化立刻执行一次handler方法
data:{
	obj:{
		words:'苹果',
		lang:'italy'
	}
},

watch: {
	数据属性名(newValue, oldValue) {
		deep: true,//深度监视
		handler(newValue){
			console.log(newValue)
		}
	}
}

案例演示:
需求:在上个案例的基础上,输入内容,修改语言,实时翻译
代码:

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>Documenttitle>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
        font-size: 18px;
      }
      #app {
        padding: 10px 20px;
      }
      .query {
        margin: 10px 0;
      }
      .box {
        display: flex;
      }
      textarea {
        width: 300px;
        height: 160px;
        font-size: 18px;
        border: 1px solid #dedede;
        outline: none;
        resize: none;
        padding: 10px;
      }
      textarea:hover {
        border: 1px solid #1589f5;
      }
      .transbox {
        width: 300px;
        height: 160px;
        background-color: #f0f0f0;
        padding: 10px;
        border: none;
      }
      .tip-box {
        width: 300px;
        height: 25px;
        line-height: 25px;
        display: flex;
      }
      .tip-box span {
        flex: 1;
        text-align: center;
      }
      .query span {
        font-size: 18px;
      }

      .input-wrap {
        position: relative;
      }
      .input-wrap span {
        position: absolute;
        right: 15px;
        bottom: 15px;
        font-size: 12px;
      }
      .input-wrap i {
        font-size: 20px;
        font-style: normal;
      }
    style>
  head>
  <body>
    <div id="app">
      
      <div class="query">
        <span>翻译成的语言:span>
        <select v-model="obj.lang">
          <option value="italy">意大利option>
          <option value="english">英语option>
          <option value="german">德语option>
        select>
      div>

      
      <div class="box">
        <div class="input-wrap">
          <textarea v-model="obj.words">textarea>
          <span><i>⌨️i>文档翻译span>
        div>
        <div class="output-wrap">
          <div class="transbox">{{ result }}div>
        div>
      div>
    div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js">script>
    <script>
      // 接口地址:https://applet-base-api-t.itheima.net/api/translate
      // 请求方式:get
      // 请求参数:
      // (1)words:需要被翻译的文本(必传)
      // (2)lang: 需要被翻译成的语言(可选)默认值-意大利
      // -----------------------------------------------
      
      const app = new Vue({
        el: '#app',
        data: {
          // words: ''
          obj: {
            words: '',
            lang:'italy'
          },

          result:'',//翻译结果
          timer: null
        },
        // 具体讲解:(1) watch语法 (2) 具体业务实现
        watch: {
          obj: {
            deep: true, //深度监视
            immediate: true, //立刻执行,一进入页面handler立刻执行
            handler( newValue ){
            //   //防抖:延迟执行 -> 干啥事先等一等,延迟一会,一段时间内没有再次触发,才执行
            clearTimeout(this.timer)
            this.timer = setTimeout(async () => {  
              //这里是ajax的内容
              const res = await axios({
              url: 'https://applet-base-api-t.itheima.net/api/translate',
              params:newValue
            })
            this.result = res.data.data 
            console.log(res.data.data)
            }, 300)
            }
          }
        }
      })
    script>
  body>
html>

综合案例 - 水果购物车

  • 案例说明:
    完成一个水果购物车网页,如图所示
    VUE学习笔记(黑马2023版 持更)_第36张图片

  • 需求说明:

  1. 渲染功能
    v-if v-else:渲染body
    v-for:遍历水果数组
    :class:设置选中的css效果
  2. 删除功能
    点击传参@click,filter过滤覆盖原数组
  3. 修改个数
    点击传参@click,find找对象
  4. 全选反选
    计算属性computed(完整写法)
  5. 统计选中的总价和总数量
    计算属性computed,reduce条件求和
  6. 持久化到本地
    watch监视,localStorage,JSON.stringify,JSON.parse
  • 完整代码:
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/inputnumber.css" />
    <link rel="stylesheet" href="./css/index.css" />
    <title>购物车title>
  head>
  <body>
    <div class="app-container" id="app">
      
      <div class="banner-box"><img src="./img/fruit.jpg" alt="" />div>
      
      <div class="breadcrumb">
        <span>span>
        /
        <span>购物车span>
      div>
      
      <div class="main" v-if="fruitList.length > 0">
        <div class="table">
          
          <div class="thead">
            <div class="tr">
              <div class="th">选中div>
              <div class="th th-pic">图片div>
              <div class="th">单价div>
              <div class="th num-th">个数div>
              <div class="th">小计div>
              <div class="th">操作div>
            div>
          div>
          
          <div class="tbody">
            <div v-for="(item, index) in fruitList" :key="item.id" class="tr" :class="{ active: item.isChecked }">
              <div class="td"><input type="checkbox" v-model="item.isChecked" />div>
              <div class="td"><img :src="item.icon" alt="" />div>
              <div class="td">{{ item.price }}div>
              <div class="td">
                <div class="my-input-number">
                  <button :disabled="item.num <= 1" class="decrease" @click="sub(item.id)"> - button>
                  <span class="my-input__inner">{{ item.num }}span>
                  <button class="increase" @click="add(item.id)"> + button>
                div>
              div>
              <div class="td">{{ item.num * item.price }}div>
              <div class="td"><button @click="del(item.id)">删除button>div>
            div>
          div>
        div>
        
        <div class="bottom">
          
          <label class="check-all">
            <input type="checkbox" v-model="isAll" />
            全选
          label>
          <div class="right-box">
            
            <span class="price-box">总价  :  ¥ <span class="price">{{totalPrice}}span>span>
            
            <button class="pay">结算( {{totalCount}} )button>
          div>
        div>
      div>
      
      <div class="empty" v-else>空空如也div>
    div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script>
      const defaultArr= [
      {
        id: 1,
        icon: './img/火龙果.png',
        isChecked: true,
        num: 2,
        price: 6,
      },
      {
        id: 2,
        icon: './img/荔枝.png',
        isChecked: false,
        num: 7,
        price: 20,
      },
      {
        id: 3,
        icon: './img/榴莲.png',
        isChecked: false,
        num: 3,
        price: 40,
      },
      {
        id: 4,
        icon: './img/鸭梨.png',
        isChecked: true,
        num: 10,
        price: 3,
      },
      {
        id: 5,
        icon: './img/樱桃.png',
        isChecked: false,
        num: 20,
        price: 34,
      }
      ]
      const app = new Vue({
        el: '#app',
        data: {
          // 水果列表
          fruitList: JSON.parse(localStorage.getItem('list')) || defaultArr,
        },
        methods:{
          del(id){
            this.fruitList = this.fruitList.filter(item => item.id !== id)
          },
          add (id) {
            const fruit = this.fruitList.find(item => item.id === id)
            fruit.num++;
          },
          sub (id) {
            const fruit = this.fruitList.find(item => item.id === id)
            fruit.num--;
          }
        },
        computed:{

          isAll:{
            get () {
              return this.fruitList.every(item => item.isChecked)
            },
            set (value) {
              //基于拿到的布尔值,要让所有的小选框同步状态
              this.fruitList.forEach(item => {
                item.isChecked = value
              });
            }
          },
          //统计选中的总数
          totalCount(){
            return this.fruitList.reduce((sum,item) => {
              if (item.isChecked){
                return sum+item.num
              }else{
                return sum
              }
            } , 0)
          },
          //统计选中的总价
          totalPrice(){
            return this.fruitList.reduce((sum,item) => {
              if(item.isChecked){
                return sum+item.num*item.price
              }else{
                return sum
              }
            }, 0)
          }

        },
        watch: {
          fruitList: {
            deep:true,
            handler(newValue){
              //将变化后的newValue存入本地(转JSON)
              localStorage.setItem('list',JSON.stringify(newValue))
            }
          }
        }
      })
    script>
  body>
html>

第三天

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

  • Vue生命周期:一个Vue实例从创建到校徽的整个过程
  • 生命周期四个阶段
  1. 创建阶段:创建响应式数据
    发送初始化渲染请求
  2. 挂载阶段:渲染模版
    操作dom
  3. 更新阶段:修改数据、更新视图
  4. 销毁阶段:销毁实例
  • 钩子函数
    Vue生命周期过程中,会自动运行一些函数,被称为生命周期钩子,让开发者可以在特定阶段运行自己的代码
    VUE学习笔记(黑马2023版 持更)_第37张图片

综合案例-小黑记账清单

  • 案例说明:完成下图页面,实现增删,消费总计,与饼图渲染功能

VUE学习笔记(黑马2023版 持更)_第38张图片

  • 核心思路分析:
  1. 基本渲染
    (1)发送请求,获取数据,封装起来,再在created中调用
    (2)将获取到的数据存到data中
    (3)结合数据,v-for进行渲染
    (4)用计算属性完成消费统计功能
  2. 添加功能
    (1)收集表单数据,用v-model进行关联
    (2)给添加按钮注册点击事件,发送添加请求
    (3)重新渲染
  3. 删除功能
    (1)给’删除’注册点击事件,传参数id
    (2)根据id发送删除请求
    (3)重新渲染
  4. 饼图渲染
    (1)在mounted中初始化echarts实例
    (2)渲染函数中setOption,动态更新饼图
  • 代码实现
DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Documenttitle>
  
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" />
  <style>
    .red {
      color: red !important;
    }

    .search {
      width: 300px;
      margin: 20px 0;
    }

    .my-form {
      display: flex;
      margin: 20px 0;
    }

    .my-form input {
      flex: 1;
      margin-right: 20px;
    }

    .table> :not(:first-child) {
      border-top: none;
    }

    .contain {
      display: flex;
      padding: 10px;
    }

    .list-box {
      flex: 1;
      padding: 0 30px;
    }

    .list-box a {
      text-decoration: none;
    }

    .echarts-box {
      width: 600px;
      height: 400px;
      padding: 30px;
      margin: 0 auto;
      border: 1px solid #ccc;
    }

    tfoot {
      font-weight: bold;
    }

    @media screen and (max-width: 1000px) {
      .contain {
        flex-wrap: wrap;
      }

      .list-box {
        width: 100%;
      }

      .echarts-box {
        margin-top: 30px;
      }
    }
  style>
head>

<body>
  <div id="app">
    <div class="contain">
      
      <div class="list-box">

        
        <form class="my-form">
          <input v-model.trim="name" type="text" class="form-control" placeholder="消费名称" />
          <input v-model.number="price" type="text" class="form-control" placeholder="消费价格" />
          <button @click="add" type="button" class="btn btn-primary">添加账单button>
        form>

        <table class="table table-hover">
          <thead>
            <tr>
              <th>编号th>
              <th>消费名称th>
              <th>消费价格th>
              <th>操作th>
            tr>
          thead>
          <tbody>
            <tr v-for="(item,index) in list" :key="item.id">
              <td>{{ index }}td>
              <td>{{ item.name }}td>
              <td :class="{ red:item.price > 500 }">{{ item.price.toFixed(2) }}td>
              <td><a @click="del(item.id)" href="javascript:;">删除a>td>
            tr>
          tbody>
          <tfoot>
            <tr>
              <td colspan="4">消费总计: {{totalPrice}}td>
            tr>
          tfoot>
        table>
      div>

      
      <div class="echarts-box" id="main">div>
    div>
  div>
  <script src="https://cdn.bootcss.com/echarts/3.7.1/echarts.min.js">script>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.js">script>
  <script>
    /**
     * 接口文档地址:
     * https://www.apifox.cn/apidoc/shared-24459455-ebb1-4fdc-8df8-0aff8dc317a8/api-53371058
     * 
     * 功能需求:
     * 1. 基本渲染
     * 2. 添加功能
     * 3. 删除功能
     * 4. 饼图渲染
     */
    const app = new Vue({
      el: '#app',
      data: {
        list: [],
        name: '',
        price: ''
      },
      created() {
        // const res = await axios.get('https://applet-base-api-t.itheima.net/bill', {
        //   params: {
        //     creator: '嘻嘻'
        //   }
        // })
        // this.list=res.data.data
        this.getlist()
      },

      mounted() {
        this.myChart = echarts.init(document.querySelector('#main'))
        this.myChart.setOption({
          //标题
          title: {
            text: '消费账单列表',
            left: 'center'
          },
          //提示框
          tooltip: {
            trigger: 'item'
          },
          //图例
          legend: {
            orient: 'vertical',
            left: 'left'
          },
          series: [
            {
              name: '消费账单',
              type: 'pie',
              radius: '50%',//圆的半径
              data: [

              ],
              emphasis: {
                itemStyle: {
                  shadowBlur: 10,
                  shadowOffsetX: 0,
                  shadowColor: 'rgba(0, 0, 0, 0.5)'
                }
              }
            }
          ]
        })
      },

      computed: {
        totalPrice() {
          return this.list.reduce((sum, item) => sum + item.price, 0)
        }

      },
      methods: {
        async getlist() {
          const res = await axios.get('https://applet-base-api-t.itheima.net/bill', {
            params: {
              creator: '嘻嘻'
            }
          })
          this.list = res.data.data

          this.myChart.setOption({
            series: [
              {
                data: this.list.map(item => ({value: item.price, name:item.name}))
              }
            ]
          })
        },
        async add() {
          if (!this.name) {
            alert('请输入消费名称')
            return
          }
          if (typeof this.price !== 'number') {
            alert('请输入正确的消费价格')
            return
          }
          const res = await axios.post('https://applet-base-api-t.itheima.net/bill', {
            creator: '嘻嘻',
            name: this.name,
            price: this.price
          })
          this.getlist()

          this.name = ''
          this.price = ''
        },

        async del(id) {
          const res = await axios.delete(`https://applet-base-api-t.itheima.net/bill/${id}`)
          this.getlist()
        }
      }
    })
  script>
body>

html>

14. 工程化开发和脚手架Vue CLI

开发Vue的两种方式:

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

脚手架的基本介绍

Vue CLI 是 Vue 官方提供的一个全局命令工具
可以帮助我们快速创建一个开发Vue项目的标准化基础架子【集成 webpack 配置】

安装教程:(前置条件需要node环境)

  1. 右键单击win开始菜单
    在这里插入图片描述
    在弹出的窗口中,选择Windows PowerShell(管理员)
  2. 在窗口中输入
npm i @vue/cli -g

VUE学习笔记(黑马2023版 持更)_第39张图片

(用yarn一直没装上,在这里选了npm)

  1. 安装完成后,用以下命令检验安装
vue --verison

出现以下信息,表示安装成功
在这里插入图片描述

创建项目和启动项目

1.打开vscode,在你想要创建项目的位置打开中断,并输入以下命令

vue create 你的项目名称

VUE学习笔记(黑马2023版 持更)_第40张图片

  1. 出现以下信息,选择第二个vue 2项目
    VUE学习笔记(黑马2023版 持更)_第41张图片
    出现以下信息,表示创建成功
    VUE学习笔记(黑马2023版 持更)_第42张图片
  2. 按照控制台的提示信息启动项目
    分别输入以下命令
cd 你的项目名称
npm run serve
  1. 进入控制台提示信息中的两个网址
    VUE学习笔记(黑马2023版 持更)_第43张图片
    出现以下画面表示运行成功
    VUE学习笔记(黑马2023版 持更)_第44张图片

15.组件化开发和根组件

  • 组件化:一个页面可以拆分成一个个组件,每个组件有着自己独立的结构、样式、行为
    好处:便于维护,利于复用,有利于提升开发效率
    组件分类:普通组件、根组件
  • 根组件:整个应用最上层的组件,包括所有普通小组件

App.vue文件(单文件组成的三个组成部分)

  1. 语法高亮插件:Vetur
  2. 三部分组成
  • template:结构(Vue2中有且只能一个元素)
  • script:js逻辑
  • style:样式(可支持less,需要装包)
    具体结构如以下代码所示
<template>
  
  <div class="app" @click="fn()">
    我是结构
  div>
template>

<script>
export default{
  methods:{
    fn(){
      alert("hello")
    }
  }
}
script>


<style lang="less">

.app {
width: 400px;
height: 400px;
background-color: pink;
}

style>
  • 安装less的方法:
    在控制台输入以下命令,即可安装成功(此处为用npm安装的方式)
npm install less-loader less --save-dev

在这里插入图片描述

16.普通组件的注册使用

组件注册的两种方式:

  1. 局部注册
  • 创建.vue文件(三个组成部分:Header,Mian,Footer)
  • 在使用的组件内导入并注册
  1. 全局注册
  • 创建.vue文件(三个组成部分)
  • main.js中进行全局注册
    eg.
//导入需要全局注册的组件
import HmButton from './components/HmButton'

//调用Vue.component进行全局注册
//Vue.component('组件名',组件对象)
Vue.component('HmButton', HmButton)

使用:

  • 当成html标签使用
<组件名>组件名>
  • 组件名规范:驼峰命名法
    eg:HmHeader

局部注册使用范例:

VUE学习笔记(黑马2023版 持更)_第45张图片


<script>
import HmHeader from './components/HmHeader.vue'
import HmMain from './components/HmMain.vue'
import HmFooter from './components/HmFooter.vue'

export default {
  components:{
    HmHeader:HmHeader,
    HmMain,
    HmFooter
  }
}
script>

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