超详细Vue-coderwhy个人学习笔记(一)(Day1-Day2)

46 篇文章 68 订阅
27 篇文章 74 订阅

必看

  • 本篇是Day1到Day2的笔记​​​​​​​

目录

一、(了解)课程介绍

课程介绍

 项目介绍

二、邂逅Vuejs

(一) 、内容概述

(二)、(理解)认识Vue.js

 1.为什么要学习Vue.js

2.简单认识一下Vuejs

(三)、(掌握)Vue.js安装

(四)、(掌握)Vue初体验

1.Hello Vuejs

2.Vue列表显示

3.案例:计数器

(五)、(理解)Vue中的MVVM

1.Vue中的MVVM

MVVM的实现原理:MVVM的实现主要是三个核心点:

2.计数器中的MVVM

(六)、(理解)Vue中的options

1.创建Vue实例传入的options

2.Vue的生命周期

三、基础语法

(一)、内容概述

(二)、(了解)定义Vue中的template

VScode中的template

(三)、(掌握)插值操作

1. Mustache

 2.v-once

 3.v-html

4.v-text

5.v-pre

6.v-cloak

(四)、绑定属性(v-bind)

1.v-bind介绍

2.(掌握)v-bind基础

 3.v-bind动态绑定class

4.(掌握)v-bind绑定class--(对象语法)

5.(了解)v-bind绑定class--(数组语法)

6.(完成) 作业:v-bind和v-for的结合--点击哪项,该项变红色

7.v-bind绑定style

8.(掌握)v-bind绑定style--对象语法

9.(了解)v-bind绑定style--数组语法

(五)、计算属性

1.(掌握)什么是计算属性?计算属性的基本使用

 2.(掌握)计算属性的复杂操作

3.(理解)计算属性的setter和getter

 4.(掌握)计算属性的缓存(计算属性和methods的对比)

(六)、(掌握)ES6补充

1.(掌握)块级作用域--let/var

2.(理解)三种方案对比(ES5没有闭包-有闭包-ES6的let)

3.(掌握)const的使用和注意点

4.(掌握)ES6对象字面量的增强写法

(七)、(掌握)事件监听v-on

1.事件监听

2.v-on基础

3.v-on参数

 4.v-on修饰符

 (八)、条件判断v-if、v-else-if、v-else

1.v-if、v-else-if、v-else

3.条件渲染案例--登录切换

4.(理解)案例小问题--登录切换input的复用

5.(掌握)v-show的使用以及和v-if的区别

(九)、遍历循环v-for

1.(掌握)v-for遍历数组

2.(掌握)v-for遍历对象

3.(理解)组件的key属性--v-for绑定key和没有绑定key的区别

 4.(掌握)数组中哪些方法是响应式的?

5.(掌握)阶段案例--图书购物车

6.(掌握) JavaScript高阶函数的使用

(十)、(掌握)表单绑定v-model

1.表单绑定v-model

 2.v-model原理

 3.v-model结合radio类型使用

4.v-model结合checkbox类型使用

 5.v-model结合select类型使用

6.input中的值绑定

7.v-model 修饰符的使用

视频对应目录


一、(了解)课程介绍

  • 课程介绍

(具体请查看资料里的xmind文件)

  •  项目介绍

 

 (这个项目的接口需找老师获取)


二、邂逅Vuejs

(一) 、内容概述

  • 认识Vuejs
    • 为什么学习Vuejs
    • 简单认识一下Vuejs
  • Vuejs安装方式
    • CDN引入
    • NPM安装管理
    • 下载和引入
  • Vuejs初体验
    • Hello Vuejs
    • Vue列表展示
    • 案例:计数器
  • Vuejs的MVVM
    • Vue中的MVVM

(二)、(理解)认识Vue.js

 1.为什么要学习Vue.js

  • 我相信每个人学习Vue的目的是各部相同的。
    • 可能你的公司正要将原有的项目使用Vue进行重构。
    • 也可能是你的公司新项目决定使用Vue的技术栈。
    • 当然,如果你现在正在换工作,你会发现招聘前端的需求中,10个有8个都对Vue有或多或少的要求。
    • 当然,作为学习者我们知道Vuejs目前非常火,可以说是前端必备的一个技能。

2.简单认识一下Vuejs

(附:Vue官网

  • Vue (读音 /vjuː/,类似于 view),不要读错。
  • Vue是一个渐进式的框架,什么是渐进式的呢?
    • 渐进式意味着你可以将Vue作为你应用的一部分嵌入其中,带来更丰富的交互体验。
    • 或者如果你希望将更多的业务逻辑使用Vue实现,那么Vue的核心库以及其生态系统。
    • 比如Core+Vue-router+Vuex,也可以满足你各种各样的需求。
  • Vue有很多特点和Web开发中常见的高级功能
    • 解耦视图和数据
    • 可复用的组件
    • 前端路由技术
    • 状态管理
    • 虚拟DOM
  • 这些特点,你不需要一个个去记住,我们在后面的学习和开发中都会慢慢体会到的,一些技术点我也会在后面进行讲解。
  • 学习Vuejs的前提?
    • 从零学习Vue开发,并不需要你具备其他类似于Angular、React,甚至是jQuery的经验。
    • 但是你需要具备一定的HTML、CSS、JavaScript基础。

(三)、(掌握)Vue.js安装

  • 使用一个框架,我们第一步要做什么呢?安装下载它
  • 安装Vue的方式有很多:
    • 方式一:直接CDN引入 你可以选择引入开发环境版本还是生产环境版本
<!-- 开发环境版本,包含了有帮助的命令行警告 --> 
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>

(开发环境:源码没有经过压缩,可以直接查看源码,学习阶段使用CDN更慢)

  • 方式二:下载和引入(前期学习使用这个,后续学习CLI使用NPM)
  • 方式三:NPM安装
    • 后续通过webpack和CLI的使用,我们使用该方式。

(四)、(掌握)Vue初体验

1.Hello Vuejs

  • 我们来做我们的第一个Vue程序,体验一下Vue的响应式
  • 代码做了什么事情?
  • 我们来阅读JavaScript代码,会发现创建了一个Vue对象。
  • 创建Vue对象的时候,传入了一些options:{}
    • {}中包含了el属性该属性决定了这个Vue对象挂载到哪一个元素上,很明显,我们这里是挂载到了id为app的元素上
    • {}中包含了data属性该属性中通常会存储一些数据
      • 这些数据可以是我们直接定义出来的,比如像上面这样。
      • 也可能是来自网络,从服务器加载的。
  • 浏览器执行代码的流程:
    • 执行到10~13行代码显然出对应的HTML
    • 执行第16行代码创建Vue实例,并且对原HTML进行解析和修改。
    • 并且,目前我们的代码是可以做到响应式的。

代码:


<body>

<div id="app">
    <h2>{{message}}</h2>
    <h1>{{name}}</h1>
</div>

<div>{{message}}</div>

<script src="../js/vue.js"></script>
<script>
    // 源码里面有类似于这样的东西 有一个Vue的类 可以往里面传一些参数 Vue的参数是对象类型
    function Vue(){

    }
</script>
<script>
    // let(变量)/const(常量)
    
    // 编程范式: 声明式编程 实例管理div时,只需声明显示什么东西
    const app = new Vue({
        el: '#app', // 用于挂载要管理的元素
        data: { // 定义数据
            message: '你好啊,李银河!',
            name: 'coderwhy'
        }
    })

    // 原始js的做法(编程范式: 命令式编程) 明确告诉一步步该如何做
    // 1.创建div元素,设置id属性

    // 2.定义一个变量叫message

    // 3.将message变量放在前面的div元素中显示

    // 4.修改message的数据: 今天天气不错!

    // 5.将修改后的数据再次替换到div元素


    // Vue的响应式 --> 可以在打印台修改 app.name='yyy'
</script>

</body>

2.Vue列表显示

  • 现在,我们来展示一个更加复杂的数据:数据列表。
    • 比如我们现在从服务器请求过来一个列表
    • 希望展示到HTML中。
  • HTML代码中,使用v-for指令
    • 该指令我们后面会详细讲解,这里先学会使用。
  • 是不是变得So Easy,我们再也不需要在JavaScript代码中完成DOM的拼接相关操作了
  • 而且,更重要的是,它还是响应式的。
    • 也就是说,当我们数组中的数据发生改变时,界面会自动改变。
    • 依然让我们打开开发者模式的console,来试一下

代码:


<div id="app">
    <ul>
        <li v-for="item in movies">{{item}}</li>
    </ul>
</div>

<script src="../js/vue.js"></script>
<script>
    const app = new Vue({
        el: '#app',
        data: {
            message: '你好啊',
            movies: ['星际穿越', '大话西游', '少年派', '盗梦空间']
        }
    })
</script>

3.案例:计数器

  • 现在,我们来实现一个小的计数器
    • 点击 + 计数器+1
    • 点击 -  计数器 -1
  • 这里,我们又要使用新的指令和属性了
    • 新的属性:methods,该属性用于在Vue对象中定义方法
    • 新的指令:@click, 该指令用于监听某个元素的点击事件,并且需要指定当发生点击时,执行的方法(方法通常是methods中定义的方法)
  • 你可能会疑惑?
    • 这些@click是什么东西?
    • Vue对象中又是定义el/data/methods,到底都有哪些东西可以定义,以及它们的作用是什么?
    • 这些疑惑在后续学习中都会一一解开。

(五)、(理解)Vue中的MVVM

1.Vue中的MVVM

  • 什么是MVVM呢?
    • 通常我们学习一个概念,最好的方式是去看维基百科(对,千万别看成了百度百科)
    • https://zh.wikipedia.org/wiki/MVVM
    • 维基百科的官方解释,我们这里不再赘述。
  • 我们直接来看Vue的MVVM(Model-View-ViewModel)

  • View层
    • 视图层
    • 在我们前端开发中,通常就是DOM层
    • 主要的作用是给用户展示各种信息
  • Model层
    • 数据层
    • 数据可能是我们固定的死数据,更多的是来自我们服务器,从网络上请求下来的数据。
    • 在我们计数器的案例中,就是后面抽取出来的obj,当然,里面的数据可能没有这么简单。
  • VueModel层:
    • 视图模型层
    • 视图模型层是View和Model沟通的桥梁
    • 一方面它实现了Data Binding,也就是数据绑定,将Model的改变实时的反应到View中
    • 另一方面它实现了DOM Listener,也就是DOM监听,当DOM发生一些事件(点击、滚动、touch等)时,可以监听到,并在需要的情况下改变对应的Data。

MVVM的实现原理:MVVM的实现主要是三个核心点:

响应式:vue如何监听data的属性变化
模板解析:vue的模板是如何被解析的
渲染:vue模板是如何被渲染成HTML的

  •  推荐文章:

        Vue中的MVVM

2.计数器中的MVVM

  • 计数器的MVVM
    • 我们的计数器中就有严格的MVVM思想
      • View依然是我们的DOM
      • Model就是我们我们抽离出来的obj
      • ViewModel就是我们创建的Vue对象实例
    • 它们之间如何工作呢?
      • 首先ViewModel通过Data Binding让obj中的数据实时的在DOM中显示。
      • 其次ViewModel通过DOM Listener来监听DOM事件,并且通过methods中的操作,来改变obj中的数据。
  • 有了Vue帮助我们完成VueModel层的任务,在后续的开发,我们就可以专注于数据的处理,以及DOM的编写工作了。

代码:

<!-- Vue中的MVVM -->

    <!----1.这是我们的View---->
    <div id="app">
        <h2>当前计数: {{counter}}</h2>
        <!--<button v-on:click="counter++">+</button>-->
        <!--<button v-on:click="counter--;">-</button>-->
        <button v-on:click="add">+</button>
        <button v-on:click="sub">-</button>
        <!--下面是语法糖写法-->
        <!--<button @click="sub">-</button>-->
    </div>

    <script src="../js/vue.js"></script>
    <script>
        // 语法糖: 简写
        // proxy

        /* ---2.这是我们的Model--- */
        const obj = {
            counter: 0,
            message: 'abc'
        }

        new Vue()

        /*
            3.创建一个 Vue 实例或 "ViewModel"
            它连接 View 与 Model
            ViewModel层的核心是Vue中的双向数据绑定
        */
        const app = new Vue({
            el: '#app',
            data: obj,
            methods: {
                add: function () {
                    console.log('add被执行');
                    this.counter++
                },
                sub: function () {
                    console.log('sub被执行');
                    this.counter--
                }
            },
            beforeCreate: function () {

            },
            created: function () {
                console.log('created');
            },
            mounted: function () {
                console.log('mounted');
            }
        })

        // 1.拿button元素

        // 2.添加监听事件
    </script>

(六)、(理解)Vue中的options

1.创建Vue实例传入的options

  • 你会发现,我们在创建Vue实例的时候,传入了一个对象options。
  • 这个options中可以包含哪些选项呢?
  • 目前掌握这些选项:
    • el:
      • 类型:string | HTMLElement
      • 作用:决定之后Vue实例会管理哪一个DOM
    • data:
      • 类型:Object | Function (组件当中data必须是一个函数
      • 作用:Vue实例对应的数据对象
    • methods:
      • 类型:{ [key: string]: Function }
      • 作用:定义属于Vue的一些方法可以在其他地方调用,也可以在指令中使用

2.Vue的生命周期

  • 生命周期: 事物从诞生到消亡的整个过程

  • 官网详细描述

  • Vue的生命周期图示

    • 英文版

  • 中文版

 

  •  在Vue源码里查看生命周期
    • vue-2.5.21\src\core\index.js 入口函数    找到instance/index

  • Vue源码\vue-2.5.21\src\core\instance\index.js

  •  Vue生命周期的意义:执行到哪个步骤之后的回调,我可以做对应的事情

  • 生命周期函数也叫hook(钩子)函数
  • 只看视频可能不太理解,用代码体会下就能理解了,推荐一些文章:

        超详细vue生命周期解析(详解)

        vue生命周期

        vue之生命周期(详细)

        vue生命周期钩子函数详解

        Vue生命周期(11个钩子函数)


三、基础语法

(一)、内容概述

  • 插值操作
  • 绑定属性
  • 计算属性
  • 事件监听
  • 条件判断
  • 循环遍历
  • 阶段案例
  • v-model

(二)、(了解)定义Vue中的template

  • VScode中的template

 

 创建

 使用(回车即可出现定义的template)


(三)、(掌握)插值操作

1. Mustache

  • 如何将data中的文本数据,插入到HTML中呢?
    • 我们已经学习过了,可以通过Mustache语法(也就是双大括号)。
    • Mustache: 胡子/胡须.
  • 我们可以像下面这样来使用,并且数据是响应式的

代码:


<div id="app">
  <h2>{{message}}</h2>
  <h2>{{message}}, 李银河!</h2>
<!-- Mustache: 胡子/胡须 -->
  <!--mustache语法中,不仅仅可以直接写变量,也可以写简单的表达式-->
  <h2>{{firstName + lastName}}</h2>
  <h2>{{firstName + ' ' + lastName}}</h2>
  <h2>{{firstName}} {{lastName}}</h2>
  <h2>{{counter * 2}}</h2>
</div>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
      firstName: 'kobe',
      lastName: 'bryant',
      counter: 100
    },
  })

  // 模板语法指的就是:写代码时,按照规定好的方式来

 2.v-once

  • 但是,在某些情况下,我们可能不希望界面随意的跟随改变
    • 这个时候,我们就可以使用一个Vue的指令
  • v-once:
    • 该指令后面不需要跟任何表达式(比如之前的v-for后面是由跟表达式的)
    • 该指令表示元素和组件(组件后面才会学习)只渲染一次,不会随着数据的改变而改变
    • 代码如下:


<div id="app">
  <h2>{{message}}</h2>
  <h2 v-once>{{message}}</h2>
</div>
<!-- v-once: 
该指令后面不需要跟任何表达式(比如之前的v-for后面是由跟表达式的)
该指令表示元素和组件(组件后面才会学习)只渲染一次,不会随着数据的改变而改变 -->
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊'
    }
  })
  // 指令的本质就是自定义属性
</script>

 3.v-html

  • 某些情况下,我们从服务器请求到的数据本身就是一个HTML代码
    • 如果我们直接通过{{}}来输出,会将HTML代码也一起输出
    • 但是我们可能希望的是按照HTML格式进行解析,并且显示对应的内容
  • 如果我们希望解析出HTML展示
    • 可以使用v-html指令
    • 该指令后面往往会跟上一个string类型
    • 会将string的html解析出来并且进行渲染

<div id="app">
  <h2>{{url}}</h2>
  <h2 v-html="url"></h2>
</div>
<!-- v-html指令
该指令后面往往会跟上一个string类型
会将string的html解析出来并且进行渲染 -->
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
      url: '<a href="http://www.baidu.com">百度一下</a>'
    }
  })
</script>

4.v-text

  • v-text作用和Mustache比较相似:都是用于将数据显示在界面中
  • v-text通常情况下,接受一个string类型


<div id="app">
  <h2>{{message}}, 李银河!</h2>
  <h2 v-text="message">, 李银河!</h2>
</div>
<!-- 
  v-text作用和Mustache比较相似:都是用于将数据显示在界面中
v-text通常情况下,接受一个string类型

 -->
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊'
    }
  })
</script>

5.v-pre

  • v-pre用于跳过这个元素和它子元素的编译过程,用于显示原本的Mustache语法
  • 比如下面的代码:
    • 第一个h2元素中的内容会被编译解析出来对应的内容
    • 第二个h2元素中会直接显示{{message}}


<div id="app">
  <h2>{{message}}</h2>
  <h2 v-pre>{{message}}</h2>
</div>
<!-- 
  v-pre用于跳过这个元素和它子元素的编译过程,用于显示原本的Mustache语法。
 -->
<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊'
    }
  })
</script>

6.v-cloak

  • 在某些情况下,我们浏览器可能会直接显然出未编译的Mustache标签。
  • cloak: 斗篷

<style>
    [v-cloak] {
      display: none;
    }
</style>

  <div id="app" v-cloak>
    <h2>{{message}}</h2>
  </div>
  <!-- 
  在某些情况下,我们浏览器可能会直接显然出未编译的Mustache标签。
cloak: 斗篷
需要和css一起搭配使用
v-cloak 指令用法
(1)插值表达式存在的问题:“闪动”
(2)如何解决该问题:使用v-cloak指令
(3)解决该问题的原理:先隐藏,替换好值之后再显示最终的值
 -->
  <script src="../js/vue.js"></script>
  <script>
    // 在vue解析之前, div中有一个属性v-cloak
    // 在vue解析之后, div中没有一个属性v-cloak
    setTimeout(function () {
      const app = new Vue({
        el: '#app',
        data: {
          message: '你好啊'
        }
      })
    }, 1000)
  </script>


(四)、绑定属性(v-bind)

1.v-bind介绍

  • 前面我们学习的指令主要作用是将值插入到我们模板的内容当中
  • 但是,除了内容需要动态来决定外,某些属性我们也希望动态来绑定。
    • 比如动态绑定a元素的href属性
    • 比如动态绑定img元素的src属性
  • 这个时候,我们可以使用v-bind指令:
    • 作用:动态绑定属性
    • 缩写:
    • 预期:any (with argument) | Object (without argument)
    • 参数:attrOrProp (optional)
  • 下面,我们就具体来学习v-bind的使用。

2.(掌握)v-bind基础

  • v-bind用于绑定一个或多个属性值,或者向另一个组件传递props值(这个学到组件时再介绍)
  • 在开发中,有哪些属性需要动态进行绑定呢?
    • 还是有很多的,比如图片的链接src、网站的链接href、动态绑定一些类、样式等等
  • 比如通过Vue实例中的data绑定元素的src和href,代码如下:


  <!-- 
    v-bind用于绑定一个或多个属性值,或者向另一个组件传递props值
   -->

<div id="app">
  <!-- 错误的做法: 这里不可以使用mustache语法-->
  <!--<img src="{{imgURL}}" alt="">-->
  
  <!-- 正确的做法: 使用v-bind指令 -->
  <img v-bind:src="imgURL" alt="">
  <a v-bind:href="aHref">百度一下</a>
  <!--<h2>{{}}</h2>-->

  <!--语法糖的写法-->
  <img :src="imgURL" alt="">
  <a :href="aHref">百度一下</a>
</div>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
      imgURL: 'https://img11.360buyimg.com/mobilecms/s350x250_jfs/t1/20559/1/1424/73138/5c125595E3cbaa3c8/74fc2f84e53a9c23.jpg!q90!cc_350x250.webp',
      aHref: 'http://www.baidu.com'
    }
  })
</script>
  •  v-bind语法糖
    • v-bind有一个对应的语法糖,也就是简写方式
    • 在开发中,我们通常会使用语法糖的形式,因为这样更加简洁。
    • 简写方式如下

 3.v-bind动态绑定class

  • 很多时候,我们希望动态的来切换class,比如:
    • 当数据为某个状态时,字体显示红色。
    • 当数据另一个状态时,字体显示黑色
  • 绑定class有两种方式
    • 对象语法
    • 数组语法

4.(掌握)v-bind绑定class--(对象语法)

  • 绑定方式:对象语法
  • 对象语法的含义是:class后面跟的是一个对象。
    • 对象语法有下面这些用法:
用法一:直接通过{}绑定一个类
<h2 :class="{'active': isActive}">Hello World</h2>

用法二:也可以通过判断,传入多个值
<h2 :class="{'active': isActive, 'line': isLine}">Hello World</h2>

用法三:和普通的类同时存在,并不冲突
注:如果isActive和isLine都为true,那么会有title/active/line三个类
<h2 class="title" :class="{'active': isActive, 'line': isLine}">Hello World</h2>

用法四:如果过于复杂,可以放在一个methods或者computed中
注:classes是一个计算属性
<h2 class="title" :class="classes">Hello World</h2>

代码:

  •  注:当key中包含特殊字符如横线“-”(不是下划线), 空格等js不支持的变量时需要用引号。 因为vue会将"{}"中的内容应用到js中处理!
<!-- 
  绑定class有两种方式:->和普通的类同时存在,并不冲突
     对象语法 
     数组语法
    都对象.数组内的属性不用加引号
 -->

  <div id="app">
    <!--<h2 class="active">{{message}}</h2>-->
 <!-- 普通用法:这种属于多此一举 -->
    <!--<h2 :class="active">{{message}}</h2>-->

 <!-- 对象语法 -->
    <!--<h2 v-bind:class="{key1: value1, key2: value2}">{{message}}</h2>-->
    <!--<h2 v-bind:class="{类名1: true, 类名2: boolean}">{{message}}</h2>-->
    <h2 class="title" v-bind:class="{active: isActive, line: isLine}">{{message}}</h2>
    <h2 class="title" v-bind:class="getClasses()">{{message}}</h2>
    <button v-on:click="btnClick">按钮</button>
  </div>

  <script src="../js/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好啊',
        isActive: true,
        isLine: true
      },
      methods: {
        btnClick: function () {
          this.isActive = !this.isActive
        },
        getClasses: function () {
          return {
            active: this.isActive,
            line: this.isLine
          }
        }
      }
    })
  </script>

5.(了解)v-bind绑定class--(数组语法)

  • 绑定方式:数组语法
    • 数组语法的含义是:class后面跟的是一个数组。
  • 数组语法有下面这些用法:
用法一:直接通过[]绑定一个类
<h2 :class="['active']">Hello World</h2>

用法二:也可以传入多个值
<h2 :class=“[‘active’, 'line']">Hello World</h2>

用法三:和普通的类同时存在,并不冲突
注:会有title/active/line三个类
<h2 class="title" :class=“[‘active’, 'line']">Hello World</h2>

用法四:如果过于复杂,可以放在一个methods或者computed中
注:classes是一个计算属性
<h2 class="title" :class="classes">Hello World</h2>

6.(完成) 作业:v-bind和v-for的结合--点击哪项,该项变红色


<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <style>
    .active {
      color: red;
    }
  </style>
</head>

<body>

  <!--作业需求: 点击列表中的哪一项, 那么该项的文字变成红色-->
  <div id="app">
    <ul>
      <li v-for="(m, index) in movies" 
      :class="{active:index==currentIndex}" 
      @click="itemClick(index)">
        {{index}}-{{m}}
      </li>
    </ul>
  </div>

  <script src="../js/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        movies: ['海王', '海尔兄弟', '火影忍者', '进击的巨人'],
        currentIndex: 0
      },
      methods: {
        itemClick(index) {
          this.currentIndex = index;
        }
      }
    })
  </script>

</body>

7.v-bind绑定style

  • 我们可以利用v-bind:style来绑定一些CSS内联样式。
  • 在写CSS属性名的时候,比如font-size
    • 我们可以使用驼峰式 (camelCase)  fontSize
    • 或短横线分隔 (kebab-case,记得用单引号括起来) ‘font-size’
  • 绑定style有两种方式:
    • 对象语法
    • 数组语法

8.(掌握)v-bind绑定style--对象语法

:style="{color: currentColor, fontSize: fontSize + 'px'}"
  • style后面跟的是一个对象类型
    • 对象的key是CSS属性名称
    • 对象的value是具体赋的值,值可以来自于data中的属性

<div id="app">
  <!--<h2 :style="{key(属性名): value(属性值)}">{{message}}</h2>-->

  <!--'50px'必须加上单引号, 否则是当做一个变量去解析-->
  <h2 :style="{fontSize: '50px'}">{{message}}</h2>

  <!--finalSize当成一个变量使用-->
  <!--<h2 :style="{fontSize: finalSize}">{{message}}</h2>-->
  <h2 :style="{fontSize: finalSize + 'px', backgroundColor: finalColor}">{{message}}</h2>
  <h2 :style="getStyles()">{{message}}</h2>
</div>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
      finalSize: 100,
      finalColor: 'red',
    },
    methods: {
      getStyles: function () {
        return {fontSize: this.finalSize + 'px', backgroundColor: this.finalColor}
      }
    }
  })
</script>

9.(了解)v-bind绑定style--数组语法

<div v-bind:style="[baseStyles, overridingStyles]"></div>
  • style后面跟的是一个数组类型
  • 多个值以,分割即可
     

<div id="app">
  <h2 :style="[baseStyle, baseStyle1]">{{message}}</h2>
</div>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
      baseStyle: {backgroundColor: 'red'},
      baseStyle1: {fontSize: '100px'},
    }
  })
</script>

(五)、计算属性

1.(掌握)什么是计算属性?计算属性的基本使用

  • 我们知道,在模板中可以直接通过插值语法显示一些data中的数据。
  • 但是在某些情况,我们可能需要对数据进行一些转化后再显示或者需要将多个数据结合起来进行显示
    • 比如我们有firstName和lastName两个变量,我们需要显示完整的名称。
    • 但是如果多个地方都需要显示完整的名称,我们就需要写多个{{firstName}} {{lastName}}
  • 我们可以将上面的代码换成计算属性:
    • OK,我们发现计算属性是写在实例的computed选项中的。

 代码:


  <div id="app">
    <h2>{{firstName + ' ' + lastName}}</h2>
    <h2>{{firstName}} {{lastName}}</h2>
    <!-- {{}} 里面也可以调用方法,需要加() -->
    <h2>{{getFullName()}}</h2>

    <!-- {{}} 里面一般用的是变量名,方法有个() 可能有点别扭,这时候就能使用计算属性 -->
    <!-- !!计算属性不用加括号 -->
    <h2>{{fullName}}</h2>
  </div>

  <script src="../js/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        firstName: 'Lebron',
        lastName: 'James'
      },
      // computed: 计算属性()
      computed: {
         // computed里面定义的也是函数,但是函数名一般不加类似于get的动词 
        //  但是它叫计算属性,所以一般起类似于属性的名字

        fullName: function () { // 这样写其实也是一个语法糖 里面有setter和getter 这个是getter
          return this.firstName + ' ' + this.lastName
        }
      },
      methods: {
        getFullName() {
          return this.firstName + ' ' + this.lastName
        }
      }
    })
  </script>

 2.(掌握)计算属性的复杂操作

  • 计算属性中也可以进行一些更加复杂的操作,比如下面的例子:

 附:高阶函数reduce的补充

代码:


<div id="app">
  <h2>总价格: {{totalPrice}}</h2>
</div>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      books: [
        {id: 110, name: 'Unix编程艺术', price: 119},
        {id: 111, name: '代码大全', price: 105},
        {id: 112, name: '深入理解计算机原理', price: 98},
        {id: 113, name: '现代操作系统', price: 87},
      ]
    },
    computed: {
      totalPrice: function () {
        let result = 0;
        for (let i=0; i < this.books.length; i++) {
          result += this.books[i].price
        }
        return result;

        // 1.第一种方式
        /*
        let total = 0
        this.books.forEach(book => {
          total += book.price * book.count
        })
        return total
        */

        // 2.第二种方式
        // let total = 0
        // for (let i in this.books) {
        //   const book = this.books[i]
        //   total += book.price * book.count
        // }
        // return total

        // 3.第三种方式
        // 高阶函数 filter/reduce/map
        return this.books.reduce((preValue, book) => {
          return preValue + book.price * book.count
        }, 0)

        // reduce的补充
        // https://www.cnblogs.com/amujoe/p/11376940.html
      }
    }
  })
</script>

3.(理解)计算属性的setter和getter

  • 每个计算属性都包含一个getter和一个setter
    • 在上面的例子中,我们只是使用getter来读取。
    • 在某些情况下,你也可以提供一个setter方法(不常用)。
    • 在需要写setter的时候,代码如下:

用到了set

 代码:


<div id="app">
  <h2>{{fullName}}</h2>
</div>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      firstName: 'Kobe',
      lastName: 'Bryant'
    },
    computed: { // computed本质是一个对象 里面可以有属性,里面的属性又是一个对象,里面又可以写方法
      // 简写
      // fullName: function () { 
      //   return this.firstName + ' ' + this.lastName
      // }
      // name: 'coderwhy'


      // 完整写法
      // 计算属性一般是没有set方法, 只读属性.
      
      // 计算属性一般实现get方法,没有实现set方法,一般不希望别人给计算属性设置值,一般直接删除set
      // 所以调用计算属性不需要加() 本质是调用属性fullname 里面的get
      fullName: { // 对象
        set: function(newValue) { // 如果想实现set方法,这里是有一个参数的
          // 可以在控制台试试 app.fullName="yang yanyan" 就会调用set
          console.log('-----', newValue);
          const names = newValue.split(' ');
          this.firstName = names[0];// 赋值
          this.lastName = names[1];
        },
        get: function () {
          return this.firstName + ' ' + this.lastName
        }
      },

      // fullName: function () { // 这个函数就是get方法
      //   return this.firstName + ' ' + this.lastName
      // }
    }
  })
</script>

 4.(掌握)计算属性的缓存(计算属性和methods的对比)

  • 我们可能会考虑这样的一个问题:
    • methods和computed看起来都可以实现我们的功能,
    • 那么为什么还要多一个计算属性这个东西呢?
    • 原因:计算属性会进行缓存,如果多次使用时,计算属性只会调用一次
  • 我们来看下面的代码:

 在浏览器控制台查看缓存:

(fullName没有变化,就调用了一次)

(fullName有变化,重新调用)

 代码:


<div id="app">
  <!--1.直接拼接: 语法过于繁琐-->
  <h2>{{firstName}} {{lastName}}</h2>

  <!--2.通过定义methods-->
  <h2>{{getFullName()}}</h2>
  <h2>{{getFullName()}}</h2>
  <h2>{{getFullName()}}</h2>
  <h2>{{getFullName()}}</h2>

  <!--3.通过computed-->
  <h2>{{fullName}}</h2>
  <h2>{{fullName}}</h2>
  <h2>{{fullName}}</h2>
  <h2>{{fullName}}</h2>
</div>

<script src="../js/vue.js"></script>
<script>
  // angular -> google
  // TypeScript(microsoft) -> ts(类型检测)
  // flow(facebook) ->
  const app = new Vue({
    el: '#app',
    data: {
      firstName: 'Kobe',
      lastName: 'Bryant'
    },
    methods: {
      getFullName: function () {
        console.log('getFullName');
        return this.firstName + ' ' + this.lastName
      }
    },
    computed: {
      fullName: function () {
        console.log('fullName');
        // 会观察有没有变化 没有变化就直接返回原来结果 而不是重新计算 有变化就重新调用一次
        // 浏览器控制台 app.fullName='why' 会再调用一次
        return this.firstName + ' ' + this.lastName
      }
    }
  })

</script>

(六)、(掌握)ES6补充

1.(掌握)块级作用域--let/var

  • 事实上var的设计可以看成JavaScript语言设计上的错误,但是这种错误多半不能修复和移除,以为需要向后兼容
    • 大概十年前BrendanEich(js的作者)就决定修复这个问题,于是他添加了一个新的关键字:let
    • 我们可以将let看成更完美的var
  • 块级作用域
    • JS中使用var来声明一个变量时,变量的作用域主要是和函数的定义有关
    • 针对于其他块定义来说是没有作用域的,比如if/for等,这在我们开发中往往会引起一些问题

  • 1.变量作用域: 变量在什么范围内是可用

  // 下面是一个代码块。{} 就是一个代码块,有没有{}对于定义变量来说没任何意义 内外都可以使用name
    {
      var name = 'why';
      console.log(name);
    }
    console.log(name); // 可以使用name

        补充JS:代码块{},及代码块的作用是什么?

  • 2.没有块级作用域引起的问题: if的块级

 if (true) {
      var name = 'why';
    }
 console.log(name);// 可以打印
if (true) {
      var name = 'why';
    }
    console.log(name);// 可以打印

    var func;
    if (true) {
      var name = 'why';
      func = function () { // 这个变量是为了打印这里的name
        console.log(name);
      }
      // func();// 可以打印
    }
    name = 'kobe'; // 这里把变量改掉了,不应该能改

    func(); // 依然可以打印
    // console.log(name);
  • 3.没有块级作用域引起的问题: for的块级

    • 监听按钮的点击


  <button>按钮1</button>
  <button>按钮2</button>
  <button>按钮3</button>
  <button>按钮4</button>
  <button>按钮5</button>

<script>
   var btns = document.getElementsByTagName('button');
        for (var i = 0; i < btns.length; i++) {
            btns[i].addEventListener('click', function () {
                console.log('第' + i + '个按钮被点击');
                // 点击了第1个,打印却是第5个,点击其他按钮也是打印第5个
                // 与上面的那个有点像,打印的i是在一个函数里面,在点击之前,这个i已经被改掉了,进行了5次循环
            })
        }
</script>

综上,if和for里面没有块级

  • 为了解决这个问题,我们一般用一个闭包
    • 闭包:内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。                

 var btns = document.getElementsByTagName('button');
    for (var i = 0; i < btns.length; i++) {
      (function (num) { // 0
        btns[i].addEventListener('click', function () {
          console.log('第' + num + '个按钮被点击');
        })
      })(i)
    }

        补充:立即执行函数

 // 立即执行函数
    (function () {

    }())
    (function () {

    })()
  • 为什么闭包可以解决问题: 函数是一个作用域.

        var name = "yyyy";

        function abc(name) {
            console.log(name);
        }
        name="why";
        abc('aaaaaa');// 无论外部怎么改变name,打印的还是aaaa
   var name = 'why'

    function abc(bbb) { // bbb = 'why'
      console.log(bbb);
    }
    abc(name);// 也不会有任何冲突 name还是why
    name = 'kobe'

补充:关于一些闭包的文章

        闭包,看这一篇就够了——带你看透闭包的本质,百发百中

        【JS】函数闭包(重点)

        前端面试题:闭包

  • 总结
    • ES5之前因为if和for都没有块级作用域的概念, 所以在很多时候, 我们都必须借助于function的作用域来解决应用外面变量的问题.
    • ES6中,加入了let, let它是有if和for的块级作用
    •  总之,记住

      • ES5中的var是没有块级作用域的(if/for) 

      • ES6中的let是由块级作用的(if/for)

 // es6写法
    const btns = document.getElementsByTagName('button')
    for (let i = 0; i < btns.length; i++) {
      btns[i].addEventListener('click', function () {
        console.log('第' + i + '个按钮被点击');
      })
    }

  •  ES6 为什么let可以呢,有它自己的作用域了 i只属于 for (let i = 0; i < btns.length; i++) {} 里面的作用域

    { i = 0
      btns[i].addEventListener('click', function () {
        console.log('第' + i + '个按钮被点击');
      })
    }
    
    { i = 1
      btns[i].addEventListener('click', function () {
        console.log('第' + i + '个按钮被点击');
      })
    }
    { i = 2
      btns[i].addEventListener('click', function () {
        console.log('第' + i + '个按钮被点击');
      })
    }
    { i = 3
      btns[i].addEventListener('click', function () {
        console.log('第' + i + '个按钮被点击');
      })
    }
    { i = 4
      btns[i].addEventListener('click', function () {
        console.log('第' + i + '个按钮被点击');
      })
    }
  • 而ES5
    // ES5
    var i = 5
    {
      btns[i].addEventListener('click', function () {
      console.log('第' + i + '个按钮被点击');
    })
    }
    
    {
      btns[i].addEventListener('click', function () {
        console.log('第' + i + '个按钮被点击');
      })
    }
    
    
    {
      btns[i].addEventListener('click', function () {
        console.log('第' + i + '个按钮被点击');
      })
    }
    
    
    {
      btns[i].addEventListener('click', function () {
        console.log('第' + i + '个按钮被点击');
      })
    }
    
    {
      btns[i].addEventListener('click', function () {
        console.log('第' + i + '个按钮被点击');
      })
    }
    

2.(理解)三种方案对比(ES5没有闭包-有闭包-ES6的let)



  <button>按钮1</button>
  <button>按钮2</button>
  <button>按钮3</button>

  <script>
    // 1.没有块级作用域引起的问题: for的块级
    // 为什么闭包可以解决问题: 函数是一个作用域.
    var btns = document.getElementsByTagName('button');
    for (var i = 0; i < btns.length; i++) {
      btns[i].addEventListener('click', function () {
        console.log('第' + i + '个按钮被点击');
      })
    }

    // 伪代码:
    // 1.情况一: ES5中没有使用闭包(错误的方式)
    i = 2 
    { // 在里面定义在外面定义都是一样的
      // i = 0
      btns[i].addEventListener('click', function () {
        console.log('第' + i + '个按钮被点击');
      })
    }

    {
      i = 1
      btns[i].addEventListener('click', function () {
        console.log('第' + i + '个按钮被点击');
      })
    }

    {
      // i = 2
      btns[i].addEventListener('click', function () {
        console.log('第' + i + '个按钮被点击');
      })
    }

    // 2.情况二: ES5中使用闭包
    var btns = document.getElementsByTagName('button');
    for (var i = 0; i < btns.length; i++) {
      (function (i) { // 0
        btns[i].addEventListener('click', function () {
          console.log('第' + i + '个按钮被点击');
        })
      })(i)
    }

    i = 100000000

    function (i) { // i = 0
      btns[i].addEventListener('click', function () {
        console.log('第' + i + '个按钮被点击');
      })
    }(0)

    function (i) { // i = 1
      btns[i].addEventListener('click', function () {
        console.log('第' + i + '个按钮被点击');
      })
    }(1)

    function (i) { // i = 2
      btns[i].addEventListener('click', function () {
        console.log('第' + i + '个按钮被点击');
      })
    }(2)

    // ES6中的let
    const btns = document.getElementsByTagName('button')
    for (let i = 0; i < btns.length; i++) {
      btns[i].addEventListener('click', function () {
        console.log('第' + i + '个按钮被点击');
      })
    }
    i = 10000000 {
      i = 0
      btns[i].addEventListener('click', function () {
        console.log('第' + i + '个按钮被点击');
      })
    }

    {
      i = 1
      btns[i].addEventListener('click', function () {
        console.log('第' + i + '个按钮被点击');
      })
    }

    {
      i = 2
      btns[i].addEventListener('click', function () {
        console.log('第' + i + '个按钮被点击');
      })
    }
  </script>

3.(掌握)const的使用和注意点

  • const关键字
    • 在很多语言中已经存在比如C/C++中主要的作用是将某个变量修饰为常量
    • 在JavaScript中也是如此使用const修饰的标识符为常量,不可以再次赋值
  • 什么时候使用const呢?
    • 当我们修饰的标识符不会被再次赋值时,就可以使用const来保证数据的安全性
  • 建议:在ES6开发中优先使用const只有需要改变某一个标识符的时候才使用let
  • const的注意
    • const注意一        
      •  const a=20;
         a=30;// 错误:不可以修改
    • const注意二
      • const name; // 错误:const修饰的标识符必须赋值


  // 1.注意一: 一旦给const修饰的标识符被赋值之后, 不能修改
  // const name = 'why';
  // name = 'abc';

  // 2.注意二: 在使用const定义标识符,必须进行赋值
  // const name;

  // 3.注意三: 常量的含义是指向的对象不能修改, 但是可以改变对象内部的属性.
  const obj = {
    name: 'why',
    age: 18,
    height: 1.88
  }
  // obj = {}
  console.log(obj);

  obj.name = 'kobe';
  obj.age = 40;
  obj.height = 1.87;

  console.log(obj);

4.(掌握)ES6对象字面量的增强写法

const obj = new Object()

  const obj = {  // 这个{} 就是对象的字面量
    name: 'why',
    age: 18,
    run: function () {
      console.log('在奔跑');
    },
    eat: function () {
      console.log('在次东西');
    }
  }
  • 1.属性的增强写法

  const name = 'why';
  const age = 18;
  const height = 1.88

        ES5的写法:

// ES5的写法
  const obj = {
    name: name,
    age: age,
    height: height
  }
 console.log(obj);

        ES6的写法:

// ES6的写法
  const obj = {
    name,
    age,
    height,
  }
  
  console.log(obj);
  • 2.函数的增强写法

        ES5的写法

 // ES5的写法
  const obj = {
    run: function () {
  
    },
    eat: function () {
  
    }
  }

        ES6的写法

// ES6
  const obj = {
    run() {

    },
    eat() {

    }
  }

(七)、(掌握)事件监听v-on

1.事件监听

  • 在前端开发中,我们需要经常和用于交互。
    • 这个时候,我们就必须监听用户发生的事件,比如点击、拖拽、键盘事件等等
    • 在Vue中如何监听事件呢?使用v-on指令
  • v-on介绍
    • 作用:绑定事件监听器
    • 缩写:@
    • 预期:Function | Inline Statement | Object
    • 参数:event
  • 下面,我们就具体来学习v-on的使用。

2.v-on基础

  • 这里,我们用一个监听按钮的点击事件,来简单看看v-on的使用
    • 下面的代码中,我们使用了v-on:click="counter++”
    • 另外,我们可以将事件指向一个在methods中定义的函数

  • 注:v-on也有对应的语法糖:
    • v-on:click可以写成@click 

 

代码:


<!-- 
  v-on介绍
作用:绑定事件监听器
缩写:@

 -->
<div id="app">
  <h2>{{counter}}</h2>
  <!--<h2 v-bind:title></h2>-->
  <!--<h2 :title></h2>-->
  
  <!--<button v-on:click="counter++">+</button>-->
  <!--<button v-on:click="counter&#45;&#45;">-</button>-->

  <!--<button v-on:click="increment">+</button>-->
  <!--<button v-on:click="decrement">-</button>-->
  <button @click="increment">+</button>
  <button @click="decrement">-</button>
</div>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      counter: 0
    },
    methods: {
      increment() {
        this.counter++
      },
      decrement() {
        this.counter--
      }
    }
  })
</script>

3.v-on参数

  • 当通过methods中定义方法,以供@click调用时,需要注意参数问题:
  • 情况一:如果该方法不需要额外参数,那么方法后的()可以不添加。
    • 但是注意:如果方法本身中有一个参数,那么会默认将原生事件event参数传递进去
  • 情况二:如果需要同时传入某个参数,同时需要event时,可以通过$event传入事件。

 

代码:


<div id="app">
  <!--1.事件调用的方法没有参数 ()可以不添加-->
  <button @click="btn1Click()">按钮1</button>

  <button @click="btn1Click">按钮1</button>

  <!--2.在事件定义时, 写方法时省略了小括号, 
    但是方法本身是需要一个参数的, 这个时候, Vue会默认将浏览器生产的event事件对象作为参数传入到方法-->
  <!--<button @click="btn2Click(123)">按钮2</button>-->   

  <!--调用时不传入参数,那么参数为undefined-->
  <!--<button @click="btn2Click()">按钮2</button>-->
  <button @click="btn2Click">按钮2</button>

  <!--3.方法定义时, 我们需要event对象, 同时又需要其他参数-->
  <!-- 在调用方式, 如何手动的获取到浏览器参数的event对象: $event-->
  <button @click="btn3Click(abc, $event)">按钮3</button>
</div>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
      abc: 123
    },
    methods: {
      btn1Click() {
        console.log("btn1Click");
      },
      btn2Click(event) {
        console.log('--------', event);
      },
      btn3Click(abc, event) {
        console.log('++++++++', abc, event);
      }
    }
  })

  // 如果函数需要参数,但是没有传入, 那么函数的形参为undefined
  // function abc(name) {
  //   console.log(name);
  // }
  //
  // abc()

 4.v-on修饰符

  • 在某些情况下,我们拿到event的目的可能是进行一些事件处理。
  • Vue提供了修饰符来帮助我们方便的处理一些事件:
    • .stop - 调用 event.stopPropagation()。
    • .prevent - 调用 event.preventDefault()。
    • .{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
    • .native - 监听组件根元素的原生事件。
    • .once - 只触发一次回调。 


<div id="app">
  <!--1. .stop修饰符的使用  停止冒泡-->
  <div @click="divClick">
    aaaaaaa
    <button @click.stop="btnClick">按钮</button>
  </div>

  <!--2. .prevent修饰符的使用 阻止默认行为-->
  <br>
  <form action="baidu">
    <input type="submit" value="提交" @click.prevent="submitClick">
  </form>

  <!--3. .监听某个键盘的键帽-->
  <input type="text" @keyup.enter="keyUp">

  <!--4. .once修饰符的使用 点击回调只会触发一次-->
  <button @click.once="btn2Click">按钮2</button>
</div>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊'
    },
    methods: {
      btnClick() {
        console.log("btnClick");
      },
      divClick() {
        console.log("divClick");
      },
      submitClick() {
        console.log('submitClick');
      },
      keyUp() {
        console.log('keyUp');
      },
      btn2Click() {
        console.log('btn2Click');
      }
    }
  })
</script>


 (八)、条件判断v-if、v-else-if、v-else

1.v-if、v-else-if、v-else

  • v-if、v-else-if、v-else
    • 这三个指令与JavaScript的条件语句if、else、else if类似。
    • Vue的条件指令可以根据表达式的值在DOM中渲染或销毁元素或组件
  • 简单的案例演示:

  • v-if的原理:
    • v-if后面的条件为false时,对应的元素以及其子元素不会渲染。
    • 也就是根本没有不会有对应的标签出现在DOM中。 

代码:

        ○ v-if的使用


<div id="app">
  <h2 v-if="isShow">
    <div>abc</div>
    <div>abc</div>
    <div>abc</div>
    <div>abc</div>
    <div>abc</div>
    {{message}}
  </h2>
</div>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
      isShow: true
    }
  })
</script>

          ○ v-if 和v-else 的使用



<div id="app">
  <h2 v-if="isShow">
    <div>abc</div>
    <div>abc</div>
    <div>abc</div>
    <div>abc</div>
    <div>abc</div>
    {{message}}
  </h2>
  <h1 v-else>isShow为false时, 显示我</h1>
</div>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
      isShow: true
    }
  })
</script>

          ○ v-if 、v-else-if和v-else 的使用



<div id="app">
  <h2 v-if="score>=90">优秀</h2>
  <h2 v-else-if="score>=80">良好</h2>
  <h2 v-else-if="score>=60">及格</h2>
  <h2 v-else>不及格</h2>

  <h1>{{result}}</h1>
</div>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      score: 99
    },
    computed: {
      result() {
        let showMessage = '';
        if (this.score >= 90) {
          showMessage = '优秀'
        } else if (this.score >= 80) {
          showMessage = '良好'
        }
        // ...
        return showMessage
      }
    }
  })
</script>

3.条件渲染案例--登录切换

  • 我们来做一个简单的小案例:
    • 用户再登录时,可以切换使用用户账号登录还是邮箱地址登录。
    • 类似如下情景:

 

 代码:


  <div id="app">
    <span v-if="isUser">
      <label for="username">用户账号</label>
      <input type="text" id="username" placeholder="用户账号">
    </span>

    <span v-else>
      <label for="email">用户邮箱</label>
      <input type="text" id="email" placeholder="用户邮箱">
    </span>
    <button @click="isUser = !isUser">切换类型</button>
  </div>

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

4.(理解)案例小问题--登录切换input的复用

  • 小问题:
    • 如果我们在有输入内容的情况下,切换了类型,我们会发现文字依然显示之前的输入的内容。
    • 但是按道理讲,我们应该切换到另外一个input元素中了。
    • 在另一个input元素中,我们并没有输入内容。
    • 为什么会出现这个问题呢? 
  • 问题解答
    • 这是因为Vue在进行DOM渲染时,出于性能考虑,会尽可能的复用已经存在的元素,而不是重新创建新的元素。

    • 在上面的案例中,Vue内部会发现原来的input元素不再使用,直接作为else中的input来使用了

  • 解决方案

    • 如果我们不希望Vue出现类似重复利用的问题,可以给对应的input添加key

    • 并且我们需要保证key的不同

代码:


<div id="app">
  <span v-if="isUser">
    <label for="username">用户账号</label>
    <input type="text" id="username" placeholder="用户账号" key="username">
  </span>
  <span v-else>
    <label for="email">用户邮箱</label>
    <input type="text" id="email" placeholder="用户邮箱" key="email">
  </span>
  <button @click="isUser = !isUser">切换类型</button>
</div>

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

5.(掌握)v-show的使用以及和v-if的区别

  • v-show的用法和v-if非常相似,也用于决定一个元素是否渲染:
  • v-if和v-show对比
  • v-if和v-show都可以决定一个元素是否渲染,那么开发中我们如何选择呢?
    • v-if当条件为false时,压根不会有对应的元素在DOM中。
    • v-show当条件为false时,仅仅是将元素的display属性设置为none而已。
  • 开发中如何选择呢?
    • 当需要在显示与隐藏之间切换很频繁时,使用v-show
    • 只有一次切换时,通过使用v-if

代码:


<div id="app">
  <!--v-if: 当条件为false时, 包含v-if指令的元素, 根本就不会存在dom中-->
  <h2 v-if="isShow" id="aaa">{{message}}</h2>

  <!--v-show: 当条件为false时, v-show只是给我们的元素添加一个行内样式: display: none-->
  <h2 v-show="isShow" id="bbb">{{message}}</h2>
</div>
<!-- 
  当需要在显示与隐藏之间切片很频繁时,使用v-show
当只有一次切换时,通过使用v-if

 -->

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({   
    el: '#app',
    data: {
      message: '你好啊',
      isShow: true
    }
  })
</script>

(九)、遍历循环v-for

1.(掌握)v-for遍历数组

  • 当我们有一组数据需要进行渲染时,我们就可以使用v-for来完成。
    • v-for的语法类似于JavaScript中的for循环。
    • 格式如下:item in items的形式。
  • 我们来看一个简单的案例:
  • 如果在遍历的过程中不需要使用索引值
    • v-for="movie in movies"
    • 依次从movies中取出movie,并且在元素的内容中,我们可以使用Mustache语法,来使用movie
  • 如果在遍历的过程中,我们需要拿到元素在数组中的索引值呢
  • 语法格式:v-for=(item, index) in items
  • 其中的index就代表了取出的item在原数组的索引值。

代码: 


<div id="app">
  <!--1.在遍历的过程中,没有使用索引值(下标值)-->
  <ul>
    <li v-for="item in names">{{item}}</li>
  </ul>

  <!--2.在遍历的过程中, 获取索引值-->
  <ul>
    <li v-for="(item, index) in names">
      {{index+1}}.{{item}}
    </li>
  </ul>
</div>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      names: ['why', 'kobe', 'james', 'curry']
    }
  })
</script>

2.(掌握)v-for遍历对象

  • v-for可以用户遍历对象:
    • 比如某个对象中存储着你的个人信息,我们希望以列表的形式显示出来。

 代码:


<div id="app">
  <!--1.在遍历对象的过程中, 如果只是获取一个值, 那么获取到的是value-->
  <ul>
    <li v-for="item in info">{{item}}</li>
  </ul>


  <!--2.获取key和value 格式: (value, key) -->
  <ul>
    <li v-for="(value, key) in info">{{value}}-{{key}}</li>
  </ul>


  <!--3.获取key和value和index 格式: (value, key, index) -->
  <ul>
    <li v-for="(value, key, index) in info">{{value}}-{{key}}-{{index}}</li>
  </ul>
</div>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      info: {
        name: 'why',
        age: 18,
        height: 1.88
      }
    }
  })
</script>

3.(理解)组件的key属性--v-for绑定key和没有绑定key的区别

  • 官方推荐我们在使用v-for时,给对应的元素或组件添加上一个:key属性。
  • 为什么需要这个key属性呢(了解)?
    • 这个其实和Vue的虚拟DOM的Diff算法有关系。
    • 这里我们借用React’s diff algorithm中的一张图来简单说明一下:

 

  •  当某一层有很多相同的节点时,也就是列表节点时,我们希望插入一个新的节点
    • 我们希望可以在B和C之间加一个F,Diff算法默认执行起来是这样的。
    • 即把C更新成F,D更新成C,E更新成D,最后再插入E,是不是很没有效率?
  • 所以我们需要使用key来给每个节点做一个唯一标识
    • Diff算法就可以正确的识别此节点
    • 找到正确的位置区插入新的节点。
  • 所以一句话,key的作用主要是为了高效的更新虚拟DOM。

 4.(掌握)数组中哪些方法是响应式的?

  • 因为Vue是响应式的,所以当数据发生变化时,Vue会自动检测数据变化,视图会发生对应的更新。
  • Vue中包含了一组观察数组编译的方法,使用它们改变数组也会触发视图的更新。
    • push()
    • pop()
    • shift()
    • unshift()
    • splice()
    • sort()
    • reverse()

 

 代码:



  <div id="app">
    <ul>
      <li v-for="item in letters">{{item}}</li>
    </ul>
    <button @click="btnClick">按钮</button>
  </div>

  <script src="../js/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        letters: ['a', 'b', 'c', 'd']
      },
      methods: {
        btnClick() {
          // 1.push方法 
          // this.letters.push('aaa')
          // this.letters.push('aaaa', 'bbbb', 'cccc')

          // 2.pop(): 删除数组中的最后一个元素
          // this.letters.pop();

          // 3.shift(): 删除数组中的第一个元素
          // this.letters.shift();

          // 4.unshift(): 在数组最前面添加元素
          // this.letters.unshift()
          // this.letters.unshift('aaa', 'bbb', 'ccc')

          // 5.splice作用: 删除元素/插入元素/替换元素
          // 删除元素: 第二个参数传入你要删除几个元素(如果没有传,就删除后面所有的元素)
          // 替换元素: 第二个参数, 表示我们要替换几个元素, 后面是用于替换前面的元素
          // 插入元素: 第二个参数, 传入0, 并且后面跟上要插入的元素
          // splice(start)
          // splice(start):
          this.letters.splice(1, 3, 'm', 'n', 'l', 'x')
          // this.letters.splice(1, 0, 'x', 'y', 'z')

          // 5.sort() 排序
          // this.letters.sort()

          // 6.reverse() 反转
          // this.letters.reverse()

          // **注意: 通过索引值修改数组中的元素 
          // Vue内部没有监听这种方式 不是响应式 数组有变化,界面无更新
          // this.letters[0] = 'bbbbbb';

          // 用其他方法
          // 法1
          // this.letters.splice(0, 1, 'bbbbbb')

          // 法2
          // set(要修改的对象, 索引值, 修改后的值)
          // Vue.set(this.letters, 0, 'bbbbbb')
        }
      }
    })


    // function sum(num1, num2) {
    //   return num1 + num2
    // }
    //

    // function sum(num1, num2, num3) {
    //   return num1 + num2 + num3
    // }

    // function sum(...num) { // 可变参数
    //   console.log(num);
    // }
    //
    // sum(20, 30, 40, 50, 601, 111, 122, 33)
  </script>

5.(掌握)阶段案例--图书购物车

  • 代码实现:HTML、CSS

  • 代码实现:JS代码 

  •  重点:
    • 价格保留两位小数 ----Vue过滤器
    • 点击数量按钮,改变对应的数量---用index区分
    • 数量最小只能减到1---动态绑定disabled属性

补充:

vue 过滤器filter(全面)

HTML代码:


  <div id="app">
    <div v-if="books.length">
      <table>
        <thead>
          <tr>
            <th></th>
            <th>书籍名称</th>
            <th>出版日期</th>
            <th>价格</th>
            <th>购买数量</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="(item, index) in books">
            <td>{{item.id}}</td>
            <td>{{item.name}}</td>
            <td>{{item.date}}</td>

            <td>
              <!-- 价格 保留两位小数 拼接 ¥ -->
              <!-- 法1  总价格那里也需要这个 所以这样写不太好 -->
              <!-- {{item.price.toFixed(2)}} -->

              <!-- 法2 调用方法 -->
              <!-- {{getFinalPrice(item.price)}} -->

              <!-- 法3 过滤器 -->
              {{item.price | showPrice}}

            </td>
            <td>
              <!-- v-bind动态绑定属性如果为true就表示有这个属性 v-bind:disabled="true" 渲染出来就是disabled 所以这里只需要一个布尔值就行 -->
              <button @click="decrement(index)" v-bind:disabled="item.count <= 1">-</button>
              {{item.count}}
              <button @click="increment(index)">+</button>
            </td>
            <td><button @click="removeHandle(index)">移除</button></td>
          </tr>
        </tbody>
      </table>
      <h2>总价格: {{totalPrice | showPrice}}</h2>
    </div>
    <h2 v-else>购物车为空</h2>

  </div>

  <script src="../js/vue.js"></script>
  <script src="main.js"></script>

CSS代码:

table {
  border: 1px solid #e9e9e9;
  border-collapse: collapse;
  border-spacing: 0;
}

th, td {
  padding: 8px 16px;
  border: 1px solid #e9e9e9;
  text-align: left;
}

th {
  background-color: #f7f7f7;
  color: #5c6b77;
  font-weight: 600;
}

JS代码:

const app = new Vue({
  el: '#app',
  data: {
    books: [
      {
        id: 1,
        name: '《算法导论》',
        date: '2006-9',
        price: 85.00,
        count: 1
      },
      {
        id: 2,
        name: '《UNIX编程艺术》',
        date: '2006-2',
        price: 59.00,
        count: 1
      },
      {
        id: 3,
        name: '《编程珠玑》',
        date: '2008-10',
        price: 39.00,
        count: 1
      },
      {
        id: 4,
        name: '《代码大全》',
        date: '2006-3',
        price: 128.00,
        count: 1
      },
    ]
  },
  methods: {
    // getFinalPrice(price) {
    //   return '¥' + price.toFixed(2)
    // }

    increment(index) {
      this.books[index].count++
    },
    decrement(index) {
      this.books[index].count--
    },
    removeHandle(index) {
      this.books.splice(index, 1)
    }
  },
  computed: {
    totalPrice() {
      let totalPrice = 0
      for (let i = 0; i < this.books.length; i++) {
        totalPrice += this.books[i].price * this.books[i].count
      }
      return totalPrice

      // 其他计算总价格方法
      // for (let i in/of this.books)
      // reduce
    }
  },
  filters: { // 过滤器
    showPrice(price) { // 参数是你要过滤的东西
      // toFixed 保留两位小数
      return '¥' + price.toFixed(2)
    }
  }
})

计算总价格其他方法 :


  computed: {
    totalPrice() {
      // 1.普通的for循环
      // let totalPrice = 0
      // for (let i = 0; i < this.books.length; i++) {
      //   totalPrice += this.books[i].price * this.books[i].count
      // }
      // return totalPrice

      // 2.for (let i in this.books)
      // let totalPrice = 0
      // for (let i in this.books) {
      //   const book = this.books[i]
      //   totalPrice += book.price * book.count
      // }
      //
      // return totalPrice

      // 3.for (let i of this.books)
      // let totalPrice = 0
      // for (let item of this.books) {
      //   totalPrice += item.price * item.count
      // }
      // return totalPrice

      return this.books.reduce(function (preValue, book) {
        return preValue + book.price * book.count
      }, 0)
    }
  },

也可以使用高阶函数reduce,下面介绍高阶函数 

6.(掌握) JavaScript高阶函数的使用

  • filter/map/reduce
// 编程范式: 命令式编程/声明式编程
// 编程范式: 面向对象编程(第一公民:对象)/函数式编程(第一公民:函数)

// filter/map/reduce

// filter中的回调函数有一个要求: 必须返回一个boolean值
// true: 当返回true时, 函数内部会自动将这次回调的n加入到新的数组中
// false: 当返回false时, 函数内部会过滤掉这次的n
const nums = [10, 20, 111, 222, 444, 40, 50]

// 高阶函数 本身参数也是一个函数
// let total = nums.filter(n => n < 100).map(n => n * 2).reduce((pre, n) => pre + n);
// console.log(total);

let total = nums.filter(function (n) {
  return n < 100
}).map(function (n) {
  return n * 2
}).reduce(function (prevValue, n) {
  return prevValue + n
}, 0)
console.log(total);

// 1.filter函数的使用
// 10, 20, 40, 50
let newNums = nums.filter(function (n) {
  return n < 100
})
// console.log(newNums);

// 2.map函数的使用
// 20, 40, 80, 100
let new2Nums = newNums.map(function (n) { // 20
  return n * 2
})
console.log(new2Nums);

// 3.reduce函数的使用
// reduce 作用对数组中所有的内容进行汇总
let total = new2Nums.reduce(function (preValue, n) {
  return preValue + n
}, 0)
console.log(total);

// 第一次: preValue 0 n 20
// 第二次: preValue 20 n 40
// 第二次: preValue 60 n 80
// 第二次: preValue 140 n 100
// 240


// 普通写法
// 1.需求: 取出所有小于100的数字
let newNums = []
for (let n of nums) {
  if (n < 100) {
    newNums.push(n)
  }
}

// 2.需求:将所有小于100的数字进行转化: 全部*2
let new2Nums = []
for (let n of newNums) {
  new2Nums.push(n * 2)
}

console.log(new2Nums);


// 3.需求:将所有new2Nums数字相加,得到最终的记过
let total = 0
for (let n of new2Nums) {
  total += n
}

console.log(total);

(十)、(掌握)表单绑定v-model

1.表单绑定v-model

  • 表单控件在实际开发中是非常常见的。特别是对于用户信息的提交,需要大量的表单。
  • Vue中使用v-model指令来实现表单元素和数据的双向绑定
  • 案例的解析:
    • 当我们在输入框输入内容时
    • 因为input中的v-model绑定了message,所以会实时将输入的内容传递给message,message发生改变。
    • 当message发生改变时,因为上面我们使用Mustache语法,将message的值插入到DOM中,所以DOM会发生响应的改变。
    • 所以,通过v-model实现了双向的绑定。

  • 当然,我们也可以将v-model用于textarea元素


<div id="app">
  <input type="text" v-model="message">
  {{message}}
</div>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊'
    }
  })
</script>

 2.v-model原理

  • v-model其实是一个语法糖,它的背后本质上是包含两个操作:
    • 1.v-bind绑定一个value属性
    • 2.v-on指令给当前元素绑定input事件
  • 也就是说下面的代码:
<input type="text" v-model="message">
  • 等同于下面的代码:
<input type="text" v-bind:value="message" v-on:input="message = $event.target.value">


  <div id="app">
    <!--<input type="text" v-model="message">-->

    <!-- 上面等同于 -->
    <!--<input type="text" :value="message" @input="valueChange">-->

    <!-- 也就是 -->
    <input type="text" :value="message" @input="message = $event.target.value">
    <h2>{{message}}</h2>
  </div>

  <script src="../js/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好啊'
      },
      methods: {
        valueChange(event) {
          this.message = event.target.value;
        }
      }
    })
  </script>

 3.v-model结合radio类型使用

  • 当存在多个单选框时

  • 单选按钮radio的value会影响v-model的值(input得有value属性,value是什么获取到的就是什么)


  <div id="app">
    <label for="male">
      <!-- 需要加相同的name 否则可以多选 -->
      <!-- <input type="radio" id="male" value="男" name="sex">男 -->
      <!-- 一旦v-moddel绑定的是同一个变量,name可以不用写 -->
      <input type="radio" id="male" value="男" v-model="sex">男
    </label>
    <label for="female">
      <input type="radio" id="female" value="女" v-model="sex">女
    </label>
    <label for="other">
      <input type="radio" id="other" value="其他" v-model="sex">其他
    </label>
    <h2>您选择的性别是: {{sex}}</h2>
  </div>

  <script src="../js/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好啊',
        sex: '女' // 可以给radio默认值
      }
    })
  </script>

4.v-model结合checkbox类型使用

  • 复选框分为两种情况:单个勾选框和多个勾选框
  • 单个勾选框
    • v-model即为布尔值
    • 此时input的value并不影响v-model的值
  • 多个复选框:
    • 当是多个复选框时,因为可以选中多个,所以对应的data中属性是一个数组
    • 当选中某一个时,就会将input的value添加到数组中。

 代码:


  <div id="app">
    <!--1.checkbox单选框 -->
    <!-- 
      v-model即为布尔值true/false。
      此时input的value并不影响v-model的值
 -->
    <label for="agree">
      <input type="checkbox" id="agree" v-model="isAgree">同意协议
    </label>
    <h2>您选择的是: {{isAgree}}</h2>
    <button :disabled="!isAgree">下一步</button>

    <!--2.checkbox多选框-->
    <!-- 
      当是多个复选框时,因为可以选中多个,所以对应的data中属性是一个数组。
      当选中某一个时,就会将input的value添加到数组中。
   -->
    <input type="checkbox" value="篮球" v-model="hobbies">篮球
    <input type="checkbox" value="足球" v-model="hobbies">足球
    <input type="checkbox" value="乒乓球" v-model="hobbies">乒乓球
    <input type="checkbox" value="羽毛球" v-model="hobbies">羽毛球
    <h2>您的爱好是: {{hobbies}}</h2>

     <!-- 值绑定 动态的给value赋值 -->
    <label v-for="item in originHobbies" :for="item">
      <input type="checkbox" :value="item" :id="item" v-model="hobbies">{{item}}
    </label>
  </div>

  <script src="../js/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好啊',
        isAgree: false, // 单选框

        hobbies: [], // 多选框,
        originHobbies: ['篮球', '足球', '乒乓球', '羽毛球', '台球', '高尔夫球']
      }
    })
  </script>

 5.v-model结合select类型使用

  • 和checkbox一样,select也分单选和多选两种情况。
  • 单选:只能选中一个值。
    • v-model绑定的是一个值。
    • 当我们选中option中的一个时,会将它对应的value赋值到mySelect中
  • 多选:可以选中多个值。
    • v-model绑定的是一个数组。
    • 当选中多个值时,就会将选中的option对应的value添加到数组mySelects中

 

 代码:


  <div id="app">
    <!--1.选择一个-->
    <!-- 
    单选:只能选中一个值。
    v-model绑定的是一个值。
    当我们选中option中的一个时,会将它对应的value赋值到mySelect中

   -->
    <!-- v-model绑定在select标签 -->
    <select name="abc" v-model="fruit">
      <option value="苹果">苹果</option>
      <option value="香蕉">香蕉</option>
      <option value="榴莲">榴莲</option>
      <option value="葡萄">葡萄</option>
    </select>
    <h2>您选择的水果是: {{fruit}}</h2>

    <!--2.选择多个-->
    <!-- 
    v-model绑定的是一个数组。
    当选中多个值时,就会将选中的option对应的value添加到数组mySelects中

   -->
    <!-- 加上multiple属性就可以多选 要按ctrl才能多选 -->
    <select name="abc" v-model="fruits" multiple>
      <option value="苹果">苹果</option>
      <option value="香蕉">香蕉</option>
      <option value="榴莲">榴莲</option>
      <option value="葡萄">葡萄</option>
    </select>
    <h2>您选择的水果是: {{fruits}}</h2>
  </div>

  <script src="../js/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        message: '你好啊',
        fruit: '香蕉',
        fruits: []
      }
    })
  </script>

6.input中的值绑定

  • 初看Vue官方值绑定的时候,我很疑惑:what the hell is that?
  • 但是仔细阅读之后,发现很简单,就是动态的给value赋值而已:
    • 我们前面的value中的值,可以回头去看一下,都是在定义input的时候直接给定的。
    • 但是真实开发中,这些input的值可能是从网络获取或定义在data中的。
    • 所以我们可以通过v-bind:value动态的给value绑定值。
    • 这不就是v-bind吗?
  • 这不就是v-bind在input中的应用吗?搞的我看了很久,搞不清他想将什么。
  • 这里不再给出对应的代码,因为会用v-bind,就会值绑定的应用了。 

7.v-model 修饰符的使用

  • lazy修饰符
    • 默认情况下,v-model默认是在input事件中同步输入框的数据的。
    • 也就是说,一旦有数据发生改变对应的data中的数据就会自动发生改变。
    • lazy修饰符可以让数据在失去焦点或者回车时才会更新
  • number修饰符
    • 默认情况下,在输入框中无论我们输入的是字母还是数字,都会被当做字符串类型进行处理。
    • 但是如果我们希望处理的是数字类型,那么最好直接将内容当做数字处理。
    • number修饰符可以让在输入框中输入的内容自动转成数字类型
  • trim修饰符
    • 如果输入的内容首尾有很多空格,通常我们希望将其去除
    • trim修饰符可以过滤内容左右两边的空格

 代码:


<div id="app">
  <!--1.修饰符: lazy 让数据在失去焦点或者回车时才会更新-->
  <input type="text" v-model.lazy="message">
  <h2>{{message}}</h2>


  <!--2.修饰符: number 让在输入框中输入的内容自动转成数字类型-->
  <input type="number" v-model.number="age">
  <h2>{{age}}-{{typeof age}}</h2>

  <!--3.修饰符: trim 过滤内容左右两边的空格-->
  <input type="text" v-model.trim="name">
  <h2>您输入的名字:{{name}}</h2>
</div>

<script src="../js/vue.js"></script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      message: '你好啊',
      age: 0,
      name: ''
    }
  })

  var age = 0
  age = '1111'
  age = '222'
</script>

视频对应目录

 

 

  • 86
    点赞
  • 271
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 22
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

coderYYY

请简单粗暴地爱我,一元一元的赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值