Vue学习笔记

本文深入探讨了Vue框架的核心特性,包括Vue的渐进式设计、Vue实例的创建、前端三要素(HTML、CSS、JavaScript)以及Vue的响应式系统。文章详细介绍了Vue的v-for指令、前端框架的发展历程、Vue与JavaScript框架的对比,以及Vue的事件处理和指令系统,如v-if、v-show、v-bind、v-on、v-model等。此外,文章还涵盖了Vue结合网络数据开发应用,使用axios进行网络请求,以及Vue CLI的使用和Ant Design Vue的安装。通过实例演示,阐述了Vue在实际项目中的应用,如计数器、图片切换、列表循环、表单元素绑定等,提供了丰富的代码示例。

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

Vue:前端体系、前后端分离

一、V前端核心分析

1、Vue概述

Vue (读音 /vjuː/,类似于 view)是一套用于构建用户界面的渐进式JavaScript框架(渐进式意味着你可以将Vue作为你应用的一部分嵌套其中),发布于2014年2月。与其他大型框架不同,Vue被设计为可以自底向上逐层应用。Vue的核心是只关注视图层,不仅易于上手,还便于与第三方库(如:vue-router:跳转,vue-resource:通信,vuex:状态管理)或既有项目整合。

Vue官网:https://v3.cn.vuejs.org/

  • SoC:关注点分离原则
    • Vue 的核心库只关注视图层,方便与第三方库或既有项目整合。
  • 网络通信:axios
  • 页面跳转:vue-router
  • 状态管理:vuex
  • Vue-UI:ICE、ElementUI
  • 集大成者:MVVM+虚拟DOM
  • 计算属性:Vue特色(利用了虚拟DOM)

2、Vue入门使用

第一个Vue

和许多JavaScript应用一样,我们从网页中需要展示的数据开始,使用VUE的起步非常简单,我们引入VUE库,创建一个VUE实例,然后通过应用的ID嵌入到我们的根元素,”EL”是元素(ELEMENT)的缩写,我们还有将数据放入一个对象,并将X修改为一个表达式,用双大括号括起来。

除了字符串,VUE对其它数据的类型也是如此,我们把这个简单商品换成一个商品数组试试看,然后我们将

改为一个无序列表,在为数组中的每个商品创建一个列表项,使用VUE的v-for指令,让每个商品拥有各自的列表项,就如:

第一个Vue1

但这还不够有说服力,现在我们从空列表开始,然后从一个实际的API获取我们的商品信息,这个API是从某个数据库中获取来的,当应用被创建时,我们会从这个API获取最新的商品信息,这就是你要从这里获取的全部。我们获取商品列表,并将它们更新到数据中,如你所见:

第一个Vue2

各项列表展示了该API返回的对象。

3、前端三要素

HTML + CSS + JS : 视图 : 给用户看,刷新后台给的数据。

3.1、结构层(HTML)

HTML (结构) :超文本标记语言(Hyper Text Markup Language) ,决定网页的结构和内容。

  • HTML 不是一种编程语言,而是一种标记语言。
  • 标记语言是一套标记标签 (markup tag)。
  • HTML 使用标记标签来描述网页。
  • HTML文档也叫做 web 页面
3.2、表现层(CSS)

CSS (表现) :层叠样式表(Cascading Style sheets) ,设定网页的表现样式。

CSS层叠样式表是一门标记语言,并不是编程语言,因此不可以自定义变量,不可以引用等,换句话说就是不具备任何语法支持,它主要缺陷如下:

  • 语法不够强大,比如无法嵌套书写,导致模块化开发中需要写很多重复的选择器;
  • 没有变量和合理的样式复用机制,使得逻辑上相关的属性值必须以字面量的形式重复输出,导致难以维护;

这就导致了我们在工作中无端增加了许多工作量。为了解决这个问题,前端开发人员会使用一种称之为[CSS预处理器]的工具,提供CSS缺失的样式层复用机制、减少冗余代码,提高样式代码的可维护性。大大提高了前端在样式上的开发效率。(例如页面在不同的时候有不同的需求,淘宝在双11和618的样式就会不一样)

3.2.1、CSS预处理器

CSS预处理器定义了一种新的语言,其基本思想是,用一种专门的编程语言,为CSS增加了一些编程的特性,将CSS作为目标生成文件,然后开发者就只要使用这种语言进行CSS的编码工作。转化成通俗易懂的话来说就是“用一种专门的编程语言,进行Web页面样式设计,再通过编译器转化为正常的CSS文件,以供项目使用”。

常用的CSS预处理器:
  • SASS:基于Ruby,通过服务端处理,功能强大。解析效率高。需要学习Ruby语言,上手难度高于LESS。
    • Sass 是一款强化 CSS 的辅助工具,它在 CSS 语法的基础上增加了变量 (variables)、嵌套 (nested rules)、混合 (mixins)、导入 (inline imports) 等高级功能,这些拓展令 CSS 更加强大与优雅。使用 Sass 以及 Sass 的样式库(如 Compass)有助于更好地组织管理样式文件,以及更高效地开发项目。
  • LESS:基于NodeJS,通过客户端处理,使用简单。功能比SASS简单,解析效率也低于SASS,但在实际开发中足够了,所以我们后台人员如果需要的话,建议使用LESS。
    • Less 是一门 CSS 预处理语言,它扩充了 CSS 语言,增加了诸如变量、混合(mixin)、函数等功能,让 CSS 更易维护、方便制作主题、扩充。Less 可以运行在 Node 或浏览器端。Less是一门动态CSS语言,使得CSS样式更加灵活地作用于Html标签还有一个重要的作用就是提高样式代码的可维护性
    • 总的来说,Less赋予了CSS逻辑运算的能力。
3.3、行为层(JavaScript)

JavaScript (行为) :是一种弱类型脚本语言,其源代码不需经过编译,而是由浏览器解释运行,用于控制网页的行为。

JavaScript一门弱类型脚本语言,其源代码在发往客户端运行之前不需经过编译,而是将文本格式的字符代码发送给浏览器由浏览器解释运行。

Native原生JS开发

原生JS开发,也就是让我们按照[ECMAScript] 标准的开发方式,简称是ES,特点是所有浏览器都支持。截止到当前博客发布时间,ES 标准已发布如下版本:

  • ES3

  • ES4 (内部,未征式发布)

  • ES5 (全浏览器支持)

  • ES6 (常用,当前主流版本: webpack打包成为ES5支持! )

  • ES7

  • ES8

  • ES9 (草案阶段)

区别就是逐步增加新特性。

TypeScript

TypeScript是一种由微软开发的自由和开源的编程语言。是一种弱类型脚本语言,其源码不需经过编译,而是由浏览器解释运行,用于控制网页的行为。它是JavaScript的一个超集,而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程。由安德斯海尔斯伯格(C#、Delphi、TypeScript 之父; .NET 创立者)主导。

该语言的特点就是除了具备ES的特性之外还纳入了许多不在标准范围内的新特性,所以会导致很多浏览器不能直接支持TypeScript语法,需要编译后(编译成JS)才能被浏览器正确执行。

4、JavaScript框架

  • jQuery: 大家熟知的JavaScript框架,优点是简化了DOM操作,缺点是DOM操作太频繁,影响前端性能;在前端眼里使用它仅仅是为了兼容IE6、7、8;
  • Angular: Google收购的前端框架,由一群Java程序员开发,其特点是将后台的MVC模式搬到了前端并增加了模块化开发的理念,与微软合作,采用TypeScript语法开发;对后台程序员友好,对前端程序员不太友好;最大的缺点是版本迭代不合理(如: 1代 -> 2代,除了名字,基本就是两个东西;截止发表博客时已推出了Angular6);
  • React: Facebook出品,一款高性能的JS前端框架;特点是提出了新概念[虚拟DOM]用于减少真实DOM操作,在内存中模拟DOM操作,有效的提升了前端渲染效率;缺点是使用复杂,因为需要额外学习一门[JSX] 语言;
  • Vue:一款渐进式JavaScript框架,所谓渐进式就是逐步实现新特性的意思,如实现模块化开发、路由、状态管理等新特性。其特点是综合了Angular (模块化)和React (虚拟DOM)的优点
  • Axios :前端通信框架;因为Vue 的边界很明确,就是为了处理DOM,所以并不具备通信能力,此时就需要额外使用一个通信框架与服务器交互;当然也可以直接选择使用jQuery提供的AJAX通信功能。

前端三大框架:Angular、React、Vue。

二、前端发展史

1、UI框架

  • Ant-Design:阿里巴巴出品,基于React的UI框架
  • ElementUI、iview、ice:饿了么出品,基于Vue的UI框架
  • BootStrap:Teitter推出的一个用于前端开发的开源工具包
  • AmazeUI:又叫“妹子UI”,一款HTML5跨屏前端框架

2、JavaScript构建工具

  • Babel:JS编译工具,主要用于浏览器不支持的ES新特性,比如用于编译TypeScript。
  • WebPack:模块打包器,主要作用就是打包、压缩、合并及按序加载。

注:以上知识点已将WebApp开发所需技能全部梳理完毕。

扩展

MVVM

image-20220420100949771

  • 异步通信为主

  • Model、View、ViewModel

  • 核心为ViewModel:

    • 能够观察到数据的变化,并对视图对应的内容进行更新
    • 能够监听到视图的变化,并能够通知数据发生改变

MVVM-1

MVVM-2

MVVM工作原理

MVVM工作原理

三、入门

参考笔记:https://gitee.com/wuyuyang_bklyyds/wustudy/tree/master/%E7%AC%94%E8%AE%B0

学前须知:

HTML

HTML(HyperText MarkUp Language)超文本标记语言,是用来制作网页的标记语言。通过使用标记来描述文档结构和表现形式的一种语言,不需要编译,直接由浏览器进行解析执行,然后把结果显示在网页上。它是网页构成的基础,你见到的所有网页都离不开HTML。

CSS

CSS(Cascading Style Sheet,可译为“层叠样式表”或“级联样式表”)是一组格式设置规则,是一种样式表 (stylesheet) 语言,(CSS语言是一种标记语言,因此不需要编译,可以直接由浏览器执行(属于浏览器解释型语言)),用于控制Web页面的外观(例如字体,颜色等等),它也可以和javascript等浏览器端脚本语言合作做出许多动态的效果。通过使用CSS样式设置页面的格式,可将页面的内容与表现形式分离。页面内容存放在HTML文档中,而用于定义表现形式的CSS规则则存放在另一个文件中或HTML文档的某一部分,通常为文件头部分。将内容与表现形式分离,不仅可使维护站点的外观更加容易,而且还可以使HTML文档代码更加简练,缩短浏览器的加载时间。

JavaScript

JavaScript 是世界上最流行的编程语言,哈哈,Javascript 之所以流行,因为在浏览器里这是唯一选择(这个倒是)。JavaScript 是一种轻量级的浏览器端解释性脚本语言(JavaScript是一种基于对象的脚本语言,它不仅可以创建对象,也能使用现有的对象),可由所有的现代浏览器解释执行。JavaScript广泛用于Web应用开发,常用来为网页添加各式各样的动态功能,为页面添加交互行为,为用户提供更流畅美观的浏览效果。通常JavaScript脚本可以直接嵌入HTML页面,但写成单独的js文件有利于结构和行为的分离。

Ajax

AJAX(Asynchronous Javascript And XML) = 异步 JavaScript 和 XML。是一种用于创建快速动态网页的技术。通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。传统的网页(不使用 AJAX)如果需要更新内容,必需重载整个网页面。
有很多使用 AJAX 的应用程序案例:新浪微博、Google 地图、开心网等等。

使用ajax将后台传入的数据展示在页面时,需要使用传统的js方法:text、innerHtml、append等,比较麻烦,所以使用Vue框架。

示例前端代码:

<script>
    $(function() {
        $.ajax({
            url: '/ajaxTestDemo/',     //请求到后台的路由
            type: 'get',     //请求方式
            //访问成功时执行的函数
            //后台传过来的数据传给了参数result
            success: function(result){   
                alert('success');
                console.log(result);
                console.log(result.status);    //数据
            },
            //访问失败时执行的函数
            error: function (result) {
                alert('error');
            }
        })
    })
</script>

AJAX 如何工作

Ajax如何工作

Ajax实现前后端分离

开发工具:

VSCode

VSCode是一款免费开源的现代化轻量级代码编辑器。

vue项目用官方推荐的HBuilderX。但是,现在市面的前端都在用VSCode,所有我Vue学习就采用VSCode。

下载

但是在下载VSCode这个工具时,由于网络问题总是下载中断或者失败,究其原因大概是因为不是国内的服务器!

首先在官网找到需要下载的文件,点击下载。

image-20211112184417071

它会跳转至一个新页面:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LybZhd72-1650422248679)(https://gitee.com/AuroraLeVi/markdown/raw/master/img/image-20211112184549424.png)]

在浏览器或者下载软件中就可以看到一个下载地址了,将其复制下来。

然后/stable地址之前的地址换为如下内容

vscode.cdn.azure.cn <--------就是左边这个

比如:更新后的地址为:http://vscode.cdn.azure.cn/stable/78a4c91400152c0f27ba4d363eb56d2835f9903a/VSCodeUserSetup-x64-1.52.1.exe

这个就是国内的镜像了点开后,你会发现速度直接起飞!

安装

下载完成单击运行,然后我们开始进行安装:一直"下一步"即可,记住要选择"添加到PATH中"(添加到系统环境变量中,如果没有勾选这个选项,则需要手动添加)。

启动

安装结束后,我们可以启动软件查看是否安装成功:

image-20211112185613146

这样一步一步的操作下来,我们的VSCode软件的下载和安装就基本上完成了!

Vscode界面介绍(主要分为5个区域,分别是活动栏,侧边栏,编辑栏,面板栏,状态栏)

img

①:活动栏从上到下依次为,打开侧边栏,搜索,使用git,debug,使用插件。

②:侧边栏,新建项目文件和文件夹。

③:编辑栏,编写代码的区域。

④:面板栏,从左到右依次为,问题,输出,调试栏,终端(terminal),最重要的是terminal,用来输入相关命令

⑤:状态栏,点击 该区域可以调出面板栏

⑥:需要注意的为下图红框所示,分别表示鼠标光标所在位置和tab缩进字符,这里为缩进4个字符

新建文件和文件夹

  • 新建文件:Ctrl+N新建文件并修改后缀即可(后缀根据所需文件来,比如.html,.css,.js等)

  • 新建文件夹

    • ①:首先根据需要指定一个路径(这里路径以桌面为例),然后新建一个文件夹(这里新建的文件夹为demo1)

    • ②:鼠标点击侧边栏第二个选项

    • ③:此时会提示你没有可以打开的文件夹,点击Open Folder按钮导入桌面新建的文件夹demo1

    • ④:把文件夹导入后发现刚刚新建文件夹名字是小写的,现在变大写了,这个不影响,不用太在意
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nDXvMaxe-1650422248694)(D:\Typera_Image\image-20211112202956985.png)]
      (上图红色框图标从左到右为,新建文件 / 新建文件夹 / 刷新 / 折叠文件)
      :新建文件一定要修改后缀,否则默认都是text文本文件。

内部插件-Live Server:为实时加载功能的小型服务器,在项目中实时用live-server作为一个实时服务器实时查看开发的网页或项目效果。

步骤:

  • Vue基础

  • 本地引用

  • 网络应用

  • 综合应用

Vue基础

Vue简介

1、JavaScript框架

2、简化DOM操作(Vue有特殊语法,不用人为写代码)

3、响应式数据驱动

第一个Vue应用

入门一个框架或者库,没有比官方文档更好的方式了!Vue官方文档

Vue官网推荐学习视频带您了解其核心概念和一个示例工程。还有一个讲解视频

① 导入 vue.js 的 script 脚本文件:

<!-- 1. 导入Vue.js的script脚本 -->
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>

② 在页面中声明一个将要被 vue 所控制的 DOM 区域:

<!-- 2. 在页面中声明将被Vue所控制的DOM区域 -->
<!-- 将来new的Vue实例,会控制这个元素中的内容 -->
<!-- Vue实例所控制的这个元素区域,就是我们MVVM中的V -->
<div id="app">
    {{ message }}
</div>

③ 创建 vm 实例对象(Vue 实例对象):el指定根element(选择器); data初始化数据(页面可以访问)。使用简洁的模板语法把数据渲染到页面上:

<script>
    
    // 3. 创建一个vm实例对象(Vue实例对象)
    // 当我们导入vue包后,在浏览器的内存中,就多了一个Vue构造函数
    // 注意:我们new出来的这个vm对象,就是我们MVVM中VM调度者
    var app = new Vue({ // data属性中,存放的是el中要用到的数据
        // 3.1 指定当前vm实例对象要控制页面的哪一个区域
        el: "#app", // 表示,当前我们new的这个Vue实例,要控制页面上的哪一个区域
        // 3.2 指定Model数据源
        // 这里的data就是我们MVVM中的M,专门用来保存每个页面的数据的
        data: {
            message: "您好!世界!" // 通过Vue提供的指令,很方便的就把数据渲染到页面上,程序员不再手动操作DOM元素了【前端Vue之类的框架,不提倡我们手动去操作DOM了!】
        }
    })
</script>

Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统。

Vue.js 使用了基于 HTML 的模板语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。所有 Vue.js 的模板都是合法的 HTML,所以能被遵循规范的浏览器和 HTML 解析器解析。

在底层的实现上,Vue 将模板编译成虚拟 DOM 渲染函数。结合响应系统,Vue 能够智能地计算出最少需要重新渲染多少组件,并把 DOM 操作次数减到最少。

总共代码:

<!-- 2. 在页面中声明将被Vue所控制的DOM区域 -->
<!-- 将来new的Vue实例,会控制这个元素中的内容 -->
<!-- Vue实例所控制的这个元素区域,就是我们MVVM中的V -->
<div id="app">
    {{ message }}
</div>

<!-- 1. 导入Vue.js的script脚本 -->
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>

<script>
    // 3. 创建一个vm实例对象(Vue实例对象)
    // 当我们导入vue包后,在浏览器的内存中,就多了一个Vue构造函数
    // 注意:我们new出来的这个vm对象,就是我们MVVM中VM调度者
    var app = new Vue({ // data属性中,存放的是el中要用到的数据
        // 3.1 指定当前vm实例对象要控制页面的哪一个区域
        el: "#app", // 表示,当前我们new的这个Vue实例,要控制页面上的哪一个区域
        // 3.2 指定Model数据源
        // 这里的data就是我们MVVM中的M,专门用来保存每个页面的数据的
        data: {
            message: "您好!世界!" // 通过Vue提供的指令,很方便的就把数据渲染到页面上,程序员不再手动操作DOM元素了【前端Vue之类的框架,不提倡我们手动去操作DOM了!】
        }
    })
</script>

image-20211112225156203

我们已经成功创建了第一个 Vue 应用!看起来这跟渲染一个字符串模板非常类似,但是 Vue 在背后做了大量工作。现在数据和 DOM 已经被建立了关联,所有东西都是响应式的

我们要怎么确认呢?打开你的浏览器的 JavaScript 控制台,并修改 app.message 的值,你将看到上例相应地更新。

基本代码与 MVVM 的对应关系:

image-20220420100554198

注意我们不再和 HTML 直接交互了。一个 Vue 应用会将其挂载到一个 DOM 元素上 (对于这个例子是 #app) 然后对其进行完全控制。那个 HTML 是我们的入口,但其余都会发生在新创建的 Vue 实例内部。

el:挂载点

el:用来设置Vue实例挂载(管理)的元素。

1、Vue实例的作用范围是什么?

在vue外部是没有用的。在el命中的元素内部是有作用的。

作用范围是el命中的元素及其内部的后代元素,外部的无效。

{{ message }}
<div id="app">
    {{ message }}
    <span>
        {{ message }}
        <!-- p标签是块级元素,会独占一行,默认情况下p标签会自动换行的 -->
        <p>
            {{ message }}
        </p>
    </span>
</div>
{{ message }}

image-20211112225556197

2、是否可以使用其他的选择器?

可以使用其他的选择器(class,id,dom等),但是建议使用id选择器。

选择器的优先级: id选择器 > class类选择器 > 标签选择器 。

id选择器:只能在页面中使用一次,同一个id属性在同一个页面中只能使用一次。

class类选择器:最常用的选择器,样式一样的情况可以公用一个类名。

标签选择器:使用HTML中的标签作为相应的选择器的名称,直接设置页面中的标签样式。

<script>
    var app = new Vue({
        // Vue的id 选择器:#foo
        el: "#app",
        // Vue的类选择器:.foo
        //el: ".app",
        // Vue的标签选择器:foo
        //el: "div",
        data: {
            message: "中国"
        }
    })
</script>

3、是否可以设置其他的dom元素呢?

mount:挂载。

可以使用其他的双标签。但不可以使用html和body,建议挂载在div上。

<script>
    var app = new Vue({
        // Vue 的挂载容器不能是 html 和 body,解决办法, 用 div 将代码包起来!
        el: "#body",
        data: {
            message: "中国"
        }
    })
</script>
el有2种写法

(1) new Vue时候配置el属性。

<!-- new Vue时候配置el属性 -->
<div id="el1">
    {{ msg1 }}
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    var vm1 = new Vue({
        el: "#el1",
        data: {
            msg1: "new Vue时候配置el属性"
        }
    })
</script>

(2) 先创建Vue实例,随后再通过vm.$mount(‘#选择’)指定el的值。

<!-- 先创建Vue实例,随后再通过vm.$mount('#选择')指定el的值 -->
<div id="el2">
    {{ msg2 }}
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    var vm2 = new Vue({
        data: {
            msg2: "先创建Vue实例,随后再通过vm.$mount('选择器')指定el的值"
        }
    })
    vm2.$mount('#el2')
</script>

image-20211112232213697

data 数据对象

Vue中用到的数据定义在data中。
data中可以写复杂类型的数据 数组、对象。
渲染复杂数据类型时,遵守js语法。

<div id="app">
    {{ message }}
    <!-- 渲染复杂数据类型时,遵守js语法 -->
    <h2>{{ school.name }} {{ school.moblie }}</h2>
    <ul>
        <li>{{ campus[0] }}</li>
        <li>{{ campus[1] }}</li>
        <li>{{ campus[2] }}</li>
        <li>{{ campus[3] }}</li>
    </ul>
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: "#app",
        // Vue中用到的数据定义在data中
        data: {
            // data中可以写复杂类型的数据 数组、对象
            message: "Hello World!",
            school: {
                name: "莱维",
                moblie: "163-997-9090"
            },
            campus: ["拉普拉斯校区","德雷克校区","东莱校区","圣堂校区"]
        }
    })
</script>
data有2种写法

(1) 对象式

<!-- 对象式 -->
<div id="app1">
    {{ message1 }}
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    var vm1 = new Vue({
        el: "#app1",
        data: {
            message1: "对象式"
        }
    })
</script>

(2) 函数式

<!-- 函数式 -->
<div id="app2">
    {{ message2 }}
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    var vm2 = new Vue({
        el: "#app2",
        data(){
            console.log('@@@',this) //此处的this是Vue实例对象
            return{
                message2: "函数式"
            }
        }
    })
</script>

如何选择:目前哪种写法都可以,以后学习到组件时,data必须使用函数式,否则会报错!

一个重要的原则:由Vue管理的函数,一定不要写箭头函数!一旦写了箭头函数,this就不再是Vue实例了。

本地应用

扩展

v-cloak:解决闪烁问题,用插值表达式,不会替换里面原来的内容。

使用 v-cloak 指令来解决屏幕闪动的问题。

在简单项目中,使用 v-cloak 指令是解决屏幕闪动的好方法。但在大型、工程化的项目中(webpack、vue-router)只有一个空的 div 元素,元素中的内容是通过路由挂载来实现的,这时我们就不需要用到 v-cloak 指令了。

<div id="app">
    <!-- v-cloak:解决闪烁问题,用插值表达式,不会替换里面原来的内容 -->
    <!-- 使用v-cloak能够解决插值表达式闪烁的问题 -->
    <p v-cloak>++++++++ {{ msg }} --------</p>
    <!-- 默认v-text是没有闪烁问题的 -->
    <!-- v-text会覆盖元素中原本的内容,但是差值表达式只会替换自己的这个占位符,不会把整个元素内容清空! -->
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            msg: "v-cloak解决插值表达式闪烁的问题"
        }
    })
</script>

使用v-cloak不会出现闪烁问题

v-pre
  • 显示原始信息跳过编译过程。
  • 跳过这个元素和它的子元素的编译过程。
  • 一些静态的内容不需要编译加这个指令可以加快渲染。
<body>
    <!-- 
显示原始信息跳过编译过程。
跳过这个元素和它的子元素的编译过程。
一些静态的内容不需要编译加这个指令可以加快渲染。
-->
    <span v-pre>{{ this will not be compiled }}</span>
    <!--  显示的是{{ this will not be compiled }}  -->
    <span v-pre>{{msg}}</span>
    <!--   即使data里面定义了msg,这里仍然是显示的{{msg}}  -->
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
        new Vue({
            el: '#app',
            data: {
                msg: 'Hello Vue.js'
            }
        });
    </script>

image-20211113203543701

v-once

v-once:执行一次性的插值【当数据改变时,插值处的内容不会继续更新】。一般用于静态内容展示。

v-once 指令除了用于展示静态内容,也可能在需要进一步优化性能时用到它。

<div id="app">
    <!-- 即使data里面定义了 msg 后期我们修改了,仍然显示的是第一次data里面存储的数据即 Hello Vue.js  -->
    <!--v-once:数据只绑定一次,不进行更新-->
    <span v-once>{{ msg }}</span>
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    new Vue({
        el: '#app',
        data: {
            msg: 'Hello Vue.js'
        }
    });
    app.msg = "Hello Vue!";
</script>

这里我遇到了问题,就是<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">引入vue脚本爆红!报错:The script element allows authors to include dynamic script and data blocks in their documents. The element does not represent content for the user.没搞明白!结果多次删除新建后,莫名其妙成功了!!!(无语)

原来是html文件的命名问题,.html前不能是英文!!!写个中文就行!

image-20211114202355653

image-20211113205933024

使用了 app.msg重新设置了内容,但并没有生效,因为我们使用了 v-once 指令。

image-20211113000537231

指令带有前缀 v-,以表示它们是 Vue 提供的特殊 attribute。

内容绑定,事件绑定

v-text指令 替换文本

设置标签的文本值(textContent)。

v-text指令 替换文本

<div id="app">
    <h2 v-text="message+'-'">共产党</h2>
    <h2 v-text="info+':'">军事</h2>
    <h2>{{ message + '-' }}共产党</h2>
    <h3>{{ 1+2 }}</h3>
    <span>1的类型:{{ typeof 1 }}</span>
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: "#app",
        data:{
            message: "中国",
            info: "秦朝"
        }
    })
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZnaGtsLW-1650422248747)(https://gitee.com/AuroraLeVi/markdown/raw/master/img/image-20211113150545061.png)]

v-text指令的作用是:设置标签的内容(textContent)。

默认写法会替换全部内容,使用插值表达式{{}}可以替换指定内容。

注意:v-text有个缺点,就是不管你h2标签里面原来的值是什么,都会被替换成message的值,所以想要不被替换的话就用另一种方法:插值表达式{{}}

插值表达式的写法{{ message }},把它写在标签内部就就可以了,它只会把大括号内的message属性值替换。

v-text指令内部支持写表达式,插值表达式也可以。

v-text 指令的缺点:会覆盖元素内部原有的内容!

{{ }} 插值表达式:在实际开发中用的最多,只是内容的占位符,不会覆盖原有的内容!

比如可以对它进行字符串的拼接。

v-html指令 解析替换v-html文本

设置标签的innerHTML。

v-html 指令的作用:可以把带有标签的字符串,渲染成真正的 HTML 内容!
注意:v-html有安全性问题!!!!
(1)在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
(2)一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!

v-html指令 解析替换v-html文本

<!-- 2.html结构 -->
<div id="app">
    <p v-html="content"></p>
    <p v-text="content"></p>
</div>
<!-- 1.开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    // 3.创建Vue实例
    var app = new Vue({
        el: "#app",
        data:{
            // content: "张会林学Java"
            content: "<a href='https://scrimba.com/learn/vuedocs'>张会林学Vue</a>"
        }
    })
</script>

image-20211113143242470

v-html指令的作用是:设置元素的innerHTML。
内容中有html结构会被解析为标签。
v-text无论内容是什么,它只会解析为文本。
解析文本使用v-text。需要解析html结构使用v-html。

v-on指令基础 为元素绑定事件

为元素绑定事件。

v-on: 简写是 @ 辅助程序员为 DOM 元素绑定事件监听,原生 DOM 对象有 onclick、oninput、onkeyup 等原生事件,替换为 vue 的事件绑定形式后,分别为:v-on:click、v-on:input、v-on:keyup…

事件种类

v-on指令 为元素绑定事件

<!-- 2. 在页面中声明将被Vue所控制的DOM区域 -->
<!-- Vue实例所控制的这个元素区域,就是我们MVVM中的V -->
<div id="app">
    <h3>{{ msg }}</h3>
    <!-- Vue执行方法的 标准 写法 -->
    <input type="button" value="v-on标准" v-on:click="doIt">
    <!-- Vue执行方法的 简写 写法 -->
    <input type="button" value="v-on简写" @click="doIt">
    <input type="button" value="双击事件" @dblclick="doIt">
    <h2 @click="changeFood">{{ food }}</h2>
</div>
<!-- 1. 导入Vue.js的script脚本 -->
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    // 3. 创建一个vm实例对象(Vue实例对象)
    // 当我们导入vue包后,在浏览器的内存中,就多了一个Vue构造函数
    // 注意:我们new出来的这个vm对象,就是我们MVVM中VM调度者
    var app = new Vue({ // data属性中,存放的是el中要用到的数据
        // 3.1 指定当前vm实例对象要控制页面的哪一个区域
        el: "#app", // 表示,当前我们new的这个Vue实例,要控制页面上的哪一个区域
        // 3.2 数据
        data:{
            food: "蛋炒饭"
        },
        // 3.3 事件
        // 这个methods属性中定义了当前Vue实例所有可用的方法
        methods:{
            // 具体的方法
            doIt:function(){
                alert("做IT");
            },
            changeFood:function(){
                // console.log(this.food);
                this.food+="很经典!"
            }
        }
    })
</script>

image-20211113151725269

v-on指令的作用:为元素绑定事件。

  • 事件名不需要写on。
  • 指令可以简写为@
  • 绑定的方法定义在methods属性中。
  • 方法内部通过this关键字可以访问定义在data中的数据。

this指的就是Vue本身,因为Vue对象有很多属性、过滤器和函数,得到实例对象后,就可以调用它的所有api 。简单理解就是调用全局的一个指针。

就好比:

String.prototype.trim = function(){
return this.replace(" ",""); // this 指的就是 当前调用的对象字符串本身
}
绑定事件并传参

在使用 v-on 指令绑定事件时,可以使用 ( ) 进行传参,示例代码如下图:

v-on绑定事件并传参

Vue中执行事件的两种写法
①标准写法
<button v-on:click="方法()">点击执行方法</button>
②简写写法
<button @click="方法()">点击执行方法</button>
事件修饰符:
// 使用  .stop  阻止冒泡
<!-- <div class="inner" @click="div1Handler">
<input type="button" value="戳他" @click.stop="btnHandler">
</div> 
-->

//  使用 .prevent 阻止默认行为
<a href="http://www.baidu.com" @click.prevent="linkClick">有问题,先去百度</a> //提交事件不再重载页面
<form v-on:submit.prevent="onSubmit"></form> // 修饰符可以串联
<a v-on:click.stop.prevent="doThat"></a> //只有修饰符 
<form v-on:submit.prevent></form> // 使用  .capture 实现捕获触发事件的机制 ,首先触发该元素
<div class="inner" @click.capture="div1Handler">
    <input type="button" value="戳他" @click="btnHandler">
</div>

// 使用 .self 实现只有点击当前元素时候,才会触发事件处理函数 
<div class="inner" @click="div1Handler">
    <input type="button" value="戳他" @click="btnHandler">
</div>

// 使用 .once 只触发一次事件处理函数
<a href="http://www.baidu.com" @click.prevent.once="linkClick">有问题,先去百度</a> 

.stop:阻止事件冒泡:
@click.stop="xxx"
.prevent:阻止默认行为,如:a标签跳转,表单提交:
@click.prevent="xxx"
.capture:实现捕获触发事件的机制(原来是冒泡,变成捕获)
@click.capture="xxx"

事件修饰符1

.self:只有点击当前元素时,才会触发事件处理函数
@click.self="xxx"
.once:只触发一次事件处理函数
@click.once="xxx"

事件修饰符2

按键修饰符

在做项目中有时会用到键盘事件,在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符。

// 只有在 `keyCode` 是 13 时调用 `vm.submit()`
<input v-on:keyup.13="submit">

// 当点击enter 时调用 `vm.submit()` 
<input v-on:keyup.enter="submit">

// 当点击enter或者space时  时调用 `vm.alertMe()` 
<input type="text" v-on:keyup.enter.space="alertMe" >

/*常用的按键修饰符
.enter =>    enter键
.tab => tab键
.delete (捕获“删除”和“退格”按键) =>  删除键
.esc => 取消键
.space =>  空格键
.up =>  上
.down =>  下
.left =>  左
.right =>  右
*/
<script>
    var vm = new Vue({
        el:"#app",
        methods: {
            submit:function(){},
            alertMe:function(){},
        }
    })

</script>

v-on的缩写和事件修饰符

在这里插入图片描述

计数器

input-num 计数器

input-num 计数器实例

<!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>计数器</title>
        <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
              integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">
        <!-- 图片css样式 -->
        <link rel="stylesheet" href="img/style.css" type="text/css">
    </head>

    <body>
        <!--
创建Vue实例时:el(挂载点),data(数据),methods(方法)
v-on指令的作用是绑定事件,简写为@
方法中通过this关键字获取data中的数据
v-text指令的作用是:设置文本的元素值,简写为{{}}
v-html指令的作用是:设置元素的innerHTML
-->
        <!-- 自定义的logo -->
        <div class="myImg">
            <img src="img/lw.png" alt="logo">
        </div>

        <!--  -->
        <div id="app">
            <div class="input-num">
                <!-- 计数器功能区域 -->
                <!-- 使用Boostrap的Glyphicons字体图标样式,实现加与减的图标 -->
                <button type="button" class="btn btn-info glyphicon glyphicon-minus" @click="sub">

                </button>
                <!-- 样式-inline-block: 既有inline的同行特性,又有block的宽度和高度特性。 -->
                <span style="font-size:12px;text-align: center;line-height:20px;margin-left:5px;width:100px;height:20px;display:inline-block;">{{ num }}</span>
                <button type="button" class="btn btn-info glyphicon glyphicon-plus" @click="add">

                </button>
            </div>
        </div>
        <!-- 1. 导入Vue.js的script脚本 -->
        <!-- 开发环境版本,包含了有帮助的命令行警告 -->
        <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
        <!-- 编码 -->
        <script>
            // 创建Vue实例
            var app = new Vue({
                el: "#app",
                data: {
                    num: 1
                },
                methods: {
                    add: function () {
                        // console.log('add');
                        if (this.num < 10) {
                            this.num++;
                        } else {
                            alert("别点了,最大啦!");
                        }

                    },
                    sub: function () {
                        // console.log('sub');
                        if (this.num > 0) {
                            this.num--;
                        } else {
                            alert("别点了,最小啦!");
                        }

                    }
                }
            })
        </script>
    </body>

</html>

image-20211113164602648

创建Vue实例时:el(挂载点),data(数据),method(方法)。
v-on指令的作用是绑定事件,简写为@。
方法的内部通过this关键字获取data中的数据。
v-text指令的作用是:设置元素的文本值,简写为{{}}。
v-html指令的作用:设置元素的innerHTML。

显示切换,属性绑定

v-show 根据表达值的真假,切换元素的显示和隐藏(操纵的是display样式

v-show:隐藏时用display:none(较高的初始渲染消耗)

v-show 根据表达值的真假,切换元素的显示和隐藏(操纵的是display样式)

<div id="app">
    <button type="button" value="切换显示状态" @click="changeIsShow">
        切换显示状态
    </button>
    <button type="button" value="累加年龄" @click="addAge">
        累加年龄
    </button>
    <img src="../img/lw.jpg" alt="动漫图片" v-show="isShow">
    <img src="../img/ha.jpg" alt="黑暗风格图片" v-show="age >= 18">
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            isShow: false,
            age: 16
        },
        methods: {
            changeIsShow: function () {
                this.isShow = !this.isShow;
            },
            addAge: function () {
                this.age++;
            }
        }
    })
</script>

image-20211113172936697

v-show指令的作用:根据真假切换元素的显示状态。
原理是修改元素的display,实现显示隐藏。
指令后面的内容,最终都会解析为布尔值。
值为true元素显示,值为false元素隐藏。
数据改变之后,对应元素的显示状态会同步更新。

可以直接传入true或者false,也可以传入data中的属性,还可以传入一个表达式。

v-if 根据表达值的真假,切换元素的显示和隐藏(操作dom元素)

v-if:每次都会重新删除或者创建元素(较高的性能消耗)

v-if 根据表达值的真假,切换元素的显示和隐藏(操作dom元素)

<div id="app">
    <button value="切换显示" @click="toggleIsShow">切换显示</button>
    <!--
	v-show 只是设置了style:display=none
	v-if 是否显示该标签
-->
    <p v-if="isShow">莱维 - v-if修饰</p>
    <p v-show="isShow">莱维 - v-show修饰</p>
    <h2 v-if="temperature >= 35">好热!!!</h2>
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            isShow: false,
            temperature: 40
        },
        methods: {
            toggleIsShow:function(){
                this.isShow = !this.isShow;
            }
        }
    })
</script>

image-20211113175159046

v-if和v-show实现的效果一样,只是底层不同,v-if是通过dom树上操作元素的存在与否实现展示或者不展示。而v-show是通过display:none属性修饰的添加与否实现展示或者不展示。

v-if可以有多种使用形式: 单路分支, 多路分支, 双路分支。
v-show 只能写一个单路形式。

实际开发中需要频繁操作的元素用v-show,反之用v-if,因为操作dom树是一种对资源消耗更大的方法!

v-if指令的作用是:根据表达值的真假,切换元素的显示状态。
本质是通过操作dom操作来切换显示状态。
表达式的值为true,元素存在于dom树中,值为false,从dom树中移除。
频繁的切换使用v-show,反之使用v-if,前者的切换消耗小。

v-show根据表达值的真假,切换元素的显示和隐藏。本质是切换元素style属性display,指令后面的内容都会解析为布尔值。

v-if根据表达值的真假,切换元素的显示和隐藏。本质是操纵DOM元素,控制是否在DOM树中。性能开销较大。

vif是操作dom直接移除的,意味着有时候会对页面布局有影响,而且v-show只是隐藏,本质上还在那里。

v-if和v-show的比较

v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此:

  • 如果需要非常频繁地切换,则使用 v-show 较好。
  • 如果在运行时条件很少改变,则使用 v-if 较好。

v-if和v-show的比较

在实际开发中,绝大多数情况,不用考虑性能问题,直接使用 v-if 就好了!!!v-if 可以单独使用,或配合 v-else 指令一起使用。

v-bind:设置元素的属性(比如src,title,class)

格式:v-bind:属性名=表达式。简写为:属性名

注意:插值表达式只能用在元素的内容节点中,不能用在元素的属性节点中!
在这里插入图片描述

可简写:

在这里插入图片描述

简单理解,就是把标签的属性也使用data中的参数进行管理,简写就是:

<div id="app">
    <!-- v-bind:是Vue中,提供的用于绑定绑定标签属性的指令 -->
    <!-- 三元表达式v-bind:class="isActive?'active':''" -->
    <!-- v-on:click="事件"事件绑定标准写法 -->
    <img v-bind:src="imgSrc" alt="logo" v-bind:title="imgTitle + ' v-bind标准写法'" v-bind:class="isActive?'active':''" v-on:click="toggleActive">
    <br>
    <!-- v-bind: 绑定标签的属性(简写) -->
    <!-- class的三元表达式写法:class="isActive?'active':''" -->
    <!-- @click="事件"事件绑定简写写法 -->
    <img :src="imgSrc" alt="logo" :title="imgTitle + ' v-bind简写写法+class的三元表达式写法'" :class="isActive?'active':''"
         @click="toggleActive">
    <br>
    <!--建议使用这种-->
    <!-- class的对象写法:c:class="{active:isActive}" -->
    <img :src="imgSrc" alt="logo" :title="imgTitle + ' v-bind简写写法+class的对象写法'" :class="{active:isActive}"
         @click="toggleActive">
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
    var app = new Vue({
        el: "#app",
        data: {
            imgSrc: "../img/logo.png",
            imgTitle: "logo",
            isActive: false
        },
        methods: {
            toggleActive:function(){
                // 对isActive取反
                this.isActive = !this.isActive;
            }
        }
    })
</script>

image-20211113193435688

v-bind指令的作用是:设置元素的属性。

  • 完整写法是v-bind:属性名
  • 简写方式省略v-bind,只保留:属性名
  • 需要动态的增删class建议使用对象的方式。
Vue中使用样式

Vue中使用样式

图片切换

运用到的知识:

①图片数组

②索引

③v-bind

④v-on

⑤v-if

1、定义图片数组

1.定义图片数组

2、添加图片索引

2.添加图片索引

3、绑定src属性

3.绑定src属性

4、图片切换逻辑

4.图片切换逻辑

5、显示状态切换

5.显示状态切换

源码
html
<!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>模板</title>
        <link rel="stylesheet" href="./css/index.css">
    </head>

    <body>
        <!--
		列表数据使用数组保存
		v-bind指令可以设置元素属性,比如src
		v-show和v-if都可以切换元素的显示状态,频繁切换用v-show
		-->
        <div id="mask">
            <div class="center">
                <h2 class="title">
                    <img src="../img/logo.png" alt="logo">
                    莱维仿生科技
                </h2>
                <!-- 图片 -->
                <!-- title是全局属性,提供额外的提示信息,当鼠标滑动到该元素时,显示定义的提示 -->
                <img :src="imgArr[index]" alt="" :title="imgTitles[tindex]">
                <!-- 左箭头 -->
                <a href="javascript:void(0)" class="left" @click="prev" v-show="index != 0">
                    <img src="../img/prev.jpg" alt="左箭头" title="向左">
                </a>
                <!-- 右箭头 -->
                <a href="javascript:void(0)" class="right" @click="next" v-show="index < imgArr.length - 1">
                    <img src="../img/next.jpg" alt="右箭头" title="向右">
                </a>
            </div>
        </div>
        <!-- 开发环境版本,包含了有帮助的命令行警告 -->
        <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
        <script>
            var vm = new Vue({
                el: "#mask",
                data: {
                    imgArr: [
                        "../img/000.jpg",
                        "../img/001.jpg",
                        "../img/002.jpg",
                        "../img/003.jpg",
                        "../img/004.jpg",
                        "../img/005.jpg",
                        "../img/006.jpg",
                        "../img/007.jpg",
                        "../img/008.jpg",
                        "../img/009.jpg",
                        "../img/010.jpg"
                    ],
                    index: 0,
                    imgTitles: [
                        "仿生鸟",
                        "仿生手",
                        "仿生耳",
                        "仿生眼",
                        "仿生船",
                        "仿生臂",
                        "仿生滑板",
                        "仿生肺",
                        "仿生鳞片",
                        "仿生蝴蝶",
                        "仿生清洁板"
                    ],
                    tindex: 0,
                },
                methods: {
                    prev: function () {
                        this.index--;
                        this.tindex--;
                    },
                    next: function () {
                        this.index++;
                        this.tindex++;
                    }
                }

            })
        </script>

    </body>

</html>
css
* {
    margin: 0;
    padding: 0;
}

html,
body,
#mask {
    width: 100%;
    height: 100%;
}

#mask {
    background-color: #c9c9c9;
    position: relative;
}

#mask .center {
    position: absolute;
    background-color: #fff;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    padding: 10px;
}

#mask .center .title {
    position: absolute;
    display: flex;
    align-items: center;
    height: 56px;
    top: -61px;
    left: 0;
    padding: 5px;
    padding-left: 10px;
    padding-bottom: 0;
    color: rgba(88, 72, 41, 0.8);
    font-size: 26px;
    font-weight: normal;
    background-color: white;
    padding-right: 50px;
    z-index: 2;
}

#mask .center .title img {
    height: 40px;
    margin-right: 10px;
}

#mask .center .title::before {
    content: "";
    position: absolute;
    width: 0;
    height: 0;
    border: 65px solid;
    border-color: transparent transparent white;
    top: -65px;
    right: -65px;
    z-index: 1;
}

#mask .center>img {
    display: block;
    width: 700px;
    height: 458px;
}

#mask .center a {
    text-decoration: none;
    width: 45px;
    height: 100px;
    position: absolute;
    top: 179px;
    vertical-align: middle;
    opacity: 0.5;
}

#mask .center a :hover {
    opacity: 0.8;
}

#mask .center .left {
    left: 15px;
    text-align: left;
    padding-right: 10px;
    border-top-right-radius: 10px;
    border-bottom-right-radius: 10px;
}

#mask .center .right {
    right: 15px;
    text-align: right;
    padding-left: 10px;
    border-top-left-radius: 10px;
    border-bottom-left-radius: 10px;
}

image-20211113225101187

列表循环,表单元素绑定

v-for 根据数据生成列表结构

根据数据生成列表结果,经常和数组一起使用,数组长度的更新是响应式同步更新到页面上的。

基于源数据多次渲染元素或模板块。

数据类型可以为数组、对象、json类型数据、嵌套类型数据。

v-for根据数据生成列表结构

v-for指令可以用来遍历数组/对象。

它可以根据data中数据的更新动态刷新视图。

<!-- 准备需要挂载的结构 -->
<div id="app">
    <button type="button" value="添加数据" @click="add">添加发明</button>
    <button type="button" value="移除数据" @click="remove">移除发明</button>
    <!-- 准备循环生成的标签 -->
    <ul>
        <!-- 
可以把 item in arr 看成  for(item:arr) 
item相当于for循环的i,可以取其它名字
-->
        <!-- 数据类型为字符串数组时 -->
        <!-- v-for="(item, index) in arr,item是源数据数组arr中的每一个元素,index为当前项的索引 -->
        <li v-for="(item,index) in arr">
            {{ index + 1 }}职称:{{ item }}
        </li>
    </ul>
    <!-- 数据类型为对象数组时 -->
    <!-- v-for="value in obj",value 表示对象的属性的值,obj就是需要遍历的对象 -->
    <h2 v-for="item in invention" v-bind:title="item.name">
        {{ item.name }}
    </h2>
    <ul>
        <!-- 数据类型为对象时 -->
        <!-- v-for="(value, key, index) in obj",key表示对象的键,index表示这个对象属性的索引 -->
        <li v-for="(item,key,index) in theory">
            {{ index + 1 }} : {{ key }}--{{ item }}
        </li>
    </ul>
    <!-- 
	key给每一个循环的列表添加一个唯一的标识,使用指令 v-bind 来绑定 key
	注意冒号":"和key之间不能有空格!
	-->
    <!-- 
	==使用v-for渲染数据的时候,一定要记得将key属性加上去, 
	并且要保证这个key的值是唯一并且不重复的==,
	它的作用就是用来唯一标识数据的每一项,提高渲染性能 
	-->
    <div v-for=" item in lists" v-bind:key="item.id">
        {{ item.id }} -- {{ item.name }}
    </div>
    <!-- 如果有id,那么我们就使用id,如果没有,我们才会选择index -->
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<!-- 创建Vue实例 -->
<script>
    var app = new Vue({
        el: "#app",
        data: {
            // 新建一个字符串数组作为演示的数据
            arr: [
                "学者",
                "教授",
                "导师",
                "博士"
            ],
            // 数据类型为对象对象数组时
            invention: [
                {
                    name: "纳米级仿生"
                },
                {
                    name: "天基级武器"
                }
            ],
            // 数据类型为对象时
            theory: {
                name: "宇宙的起源",
                influence: "开辟新时代",
                outcome: "必学理论"
            },
            lists: [
                {
                    id:1,
                    name: "数组"
                },
                {
                    id:2,
                    name: "列表"
                },
                {
                    id:3,
                    name: "集合"
                }
            ]
        },
        methods: {
            // 增加数据的方法
            add: function () {
                this.invention.push({
                    name: "起源级能源"
                })
            },
            remove: function () {
                // shift() 方法用于把数组的第一个元素从其中删除,并返回第一个元素的值
                this.invention.shift();
            }
        }
    })
</script>

(item,index) in arrObj是固定搭配。in不可改变,是关键字。()中如果有一个参数,则代表arrObj中的元素;如果有两个参数,则第一个代表arrObj中的元素,第二个代表元素的下标。item和index都是见名知意的命名,但是可以改变。

image-20211114140211585

1、遍历数组
1.1、使用方式: v-for=“item in arr”,item是一个参数,表示数组中的每一项,arr也是一个参数,表示你要遍历的数组。
1.2、使用方式: v-for=“(item, index) in arr”,index表示数组项的索引。

2、遍历对象
2.1、使用方式:v-for=“value in obj”,value 表示对象的属性的值,obj就是需要遍历的对象。
2.2、使用方式:v-for=“(value, key, index) in obj”,key表示对象的键,index表示这个对象属性的索引,类似上面的数组的index。

注意:使用下面两种方式不能够动态刷新视图。

1、使用数组的length属性去更改数组的时候不行!

2、使用索引的方式去更改数组也不行!

解决方式:

1、Vue.set(arr, index, value)方法。arr:表示需要设置的数组,index表示数组索引,value表示该索引项的新的值。

  • 例如:Vue.set(vm.list, 0, {id: 111, name: ‘jack’})

2、直接调用数组的splice()方法。

注意: 使用v-for渲染数据的时候,一定要记得将key属性加上去, 并且要保证这个key的值是唯一并且不重复的,它的作用就是用来唯一标识数据的每一项,提高渲染性能。

使用v-for渲染数据的时候一定要记得将key属性加上去

v-for指令的作用是:根据数据生成列表结构。
数组经常和v-for结合使用。
语法是 ( item,index ) in 数据。
item 和 index 可以结合其他指令一起使用。
数组长度的更新会同步到页面上,是响应式的。

v-on补充 传递自定义参数,事件修饰符

事件绑定的方法协同函数调用的形式,可以传递自定义参数;.事件修饰符可以对事件进行限制。

https://cn.vuejs.org/v2/api/#v-on

v-on补充 传递自定义参数,事件修饰符

<!-- 准备需要被挂载的div -->
<!-- v-on方法让函数添加参数 -->
<div id="app">
    <button type="button" value="单击" @click="doIt(666,'老铁!')">点击</button>
    <!-- (@keyup事件触发,@keyup是一些按键松开的操作)键修饰符,键别名 -->
    <input id="hello" type="text" @keyup.enter="sayHello()">
    <!-- 键修饰符,键代码 -->
    <!-- <input type="text" @keyup.13="sayHello"> -->
</div>
<!-- 1.开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<!-- 创建一个Vue实例 -->
<script>
    var app = new Vue({
        // 通过el属性挂载元素
        el: "#app",
        methods: {
            doIt:function(p1,p2){
                console.log("做IT行业");
                console.log(p1);
                console.log(p2);
            },
            sayHello:function(){
                alert("你好!");
            }
        }
    })
</script>

image-20211114144222009

事件绑定的方法写成函数调用的形式,可以传入自定义参数。
定义方法时需要定义形参来接收传入的实参。
事件的后面跟上 .修饰符 可以对事件进行限制。
.enter 可以限制触发的按键为回车。
事件修饰符有多种。

v-model 获取和设置表单元素的值(双向数据绑定)

什么是表单元素:表单里的元素都是表单元素,譬如:input、select等。

在这里插入图片描述

<!--
v-model指令的作用是便捷的设置和获取表单元素的值
绑定的数据会和表单元素的值相关联
绑定的数据 <-> 表单元素的数据
-->
<!-- 被挂载的html结构 -->
<div id="app">
    <input type="button" value="修改message的值" @click="setMessage">
    <input type="text" v-model="message" @keyup.enter="getMessage">
    <h2>{{ message }}</h2>
</div>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<!-- Vue实例 -->
<script>
    var app = new Vue({
        // 通过el属性挂载给div元素
        el: "#app",
        data: {
            message:"学者"
        },
        methods: {
            getMessage:function(){
                alert(this.message);
            },
            setMessage:function(){
                this.message = "hello";
            }
        }

    })
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NipFxeoB-1650422248887)(https://gitee.com/AuroraLeVi/markdown/raw/master/img/image-20211114150500537.png)]

简单来说,就是将输入框和data中的元素进行绑定。data发生改变,输入框中的内容也会随之改变。反之亦然。

记事本

列表结构可以通过v-for指令结合数据生成。
v-on结合事件修饰符可以对事件进行限制,比如.enter
v-on在绑定事件时可以传递自定义参数。
通过v-model可以快速的设置和获取表单元素的值基于数据的开发方式。

计事本demo

新增

记事本-新增

删除

记事本-删除

统计

记事本-统计

清空

记事本-清空

隐藏

记事本-隐藏

代码
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>记事本模板</title>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
        <meta name="robots" content="noindex, nofollow" />
        <meta name="googlebot" content="noindex, nofollow" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="stylesheet" type="text/css" href="./css/notebook.css" />
    </head>
    <body>

        <!-- 主体区域 -->
        <!-- <section> 标签定义文档中的节(section、区段)。比如章节、页眉、页脚或文档中的其他部分。 -->
        <section id="todoapp">
            <!-- 输入框 -->
            <!-- <header> 标签定义文档的页眉(介绍信息) -->
            <header class="header">
                <h1>嘉恩笔记本</h1>
                <!-- 
autofocus 属性规定当页面加载时 input 元素应该自动获得焦点
autofocus属性对于所有输入类型来说都十分常用,它仅在页面被加载时作用于指定元素,例如一个文本输入栏,光标应该已经置于这个输入栏中并为用户输入做好了准备
-->
                <!-- 
autocomplete 属性规定输入字段是否应该启用自动完成功能,其含义代表是否让浏览器自动记录之前输入的值
自动完成允许浏览器预测对字段的输入。当用户在字段开始键入时,浏览器基于之前键入过的值,应该显示出在字段中填写的选项
off-----禁用自动完成 系统需要保密的情况下可以使用此参数
-->
                <!-- v-model双向绑定 -->
                <input v-model="inputValue" @keyup.enter="add" autofocus="autofocus" autocomplete="off" placeholder="请输入任务" class="new-todo">
            </header>
            <!-- 列表区域 -->
            <section class="main">
                <ul class="todo-list">
                    <li class=" todo" v-for="(item,index) in list">
                        <div class="view">
                            <span class="index">{{ index + 1 }}</span>
                            <label>{{ item }}</label>
                            <button class="destroy" @click="remove(index)"></button>
                        </div>
                    </li>
                </ul>
            </section>
            <!-- 统计和清空 -->
            <footer class="footer">
                <span class="todo-count" v-if="list.length!=0"><strong>{{ list.length }}</strong>items lefts</span>
                <button class="clear-completed" @click="clear" v-show="list.length!=0">
                    Clear
                </button>
            </footer>
        </section>
        <!-- 底部 -->
        <footer class="info">
            <p>
                <a href="https://cn.vuejs.org/v2/guide/">
                    <img src="../img/black.png" alt="链接到Vue官网图片">
                </a>
            </p>
        </footer>
        <!-- 开发环境版本,包含了有帮助的命令行警告 -->
        <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
        <script>
            var app = new Vue({
                el: "#todoapp",
                data: {
                    list:["练功","实验","读书"],
                    // 准备一个表单双向绑定的默认值
                    inputValue:"睡觉"
                },
                methods: {
                    add:function(){
                        this.list.push(this.inputValue);
                        // 如果想实现回车后输入框清空,则在add函数下再加一段“this.inputValue=''”
                        this.inputValue='';
                    },
                    remove:function(index){
                        // console.log("删除");
                        // console.log(index);
                        // splice() 方法向/从数组添加/删除项目,并返回删除的项目
                        // list.splice(index,1) index:点谁删除谁;1:一次删除一个
                        this.list.splice(index,1);
                    },
                    clear:function(){
                        this.list = [];
                    }
                }
            })
        </script>

    </body>
</html>

image-20211114164600668

网络应用

Vue结合网络数据开发应用

前面我们学习了Vue的本地应用,但是现阶段本地应用已经很少了,一般的应用或多或少都会进行网络数据的交互。

所以我们这次学习Vue的网络应用,学习在Vue中怎样结合网络数据进行应用的开发(重点)

首先我们需要学习一个网络请求库:axios ,学习通过axios来发送请求以及接受响应内容。

向服务器请求数据的时候,可以使用Ajax, XHR,vue-resourse,axios。

由于Vue是不操作DOM元素的,可以使用 vue-resourse和axios。但是2.0推荐使用axios。

ajax, jqueryAjax, fetch,axios对比

ajax

  • 优点:局部更新;原生支持
  • 缺点:可能破坏浏览器后退功能;嵌套回调难处理。

jqueryAjax

  • 在原生的ajax的基础上进行了封装;支持jsonp。

fetch

  • 优点:解决回调地狱。
  • 缺点:API 偏底层,需要封装;默认不带Cookie,需要手动添加;浏览器支持情况不是很友好,需要第三方的ployfill。

axios

几乎完美。

Vue网络应用

axios 功能强大的网络请求库

axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 Node.js 中,是一款功能强大的网络请求库(个人认为axios是通过promise实现对ajax技术的一种封装,就像jQuery实现ajax封装一样)。

Vue 最好使用 npm install axios 进行 下载 用 import 进行引用。

axios的使用

基本使用:
(在网页中)首先需要引入cdn:
<!--axios官网提供的在线地址-->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
axios发送get请求的语法:
axios.get(地址).then(function(response){  },function(err){  })  //不带参数
axios.get(地址?key1=value1&key2=value2).then(function(response){  },function(err){  })  //带参数
axios发送post请求的语法:
axios.post(地址).then(function(response){  },function(err){  })  //不带参数
axios.post(地址,{key1:value1,key2:value2}).then(function(response){  },function(err){  })  //带参数

其中,第一个回调函数function(response){} 会在响应完成后触发,第二个回调函数function(err){} 会在请求失败的时候触发。方法中的形参可以用来获取内容,一个是获取服务器响应的信息,一个是获取错误的信息。

key是由接口文档提供,而value是具体传输的数据。

前提:必须保证联网状态!!!

下面我们使用axios+vue来开发一个简单网络应用:

网络应用的核心,就是定义在data的数据一部分是通过网络获取到的,故我们在方法中发送网络请求,再把服务器响应后返回的数据设置到data中对应的值。

所需接口

下面是要用到的接口:

axios+vue做项目需要的两个接口

demo

接下来通过简单小Demo来感受下axios的用法:

<input type="button" value="get请求" class="get">
<input type="button" value="post请求" class="post">
<!--axios官网提供的在线地址-->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
    /*
        接口1:随机获取一条笑话
        请求地址:https://autumnfish.cn/api/joke/list
        请求方式:get
        请求参数:num(笑话条数,数字)
        响应内容:随机笑话
        */
    //   绑定事件到get请求按钮上 
    document.querySelector(".get").onclick = function () {
        axios.get("https://autumnfish.cn/api/joke/list?num=3")
            .then(function (response) {
            console.log(response);
        }, function (err) {
            console.log(err);
        })
    }
    /*
        接口2:随机获取一条笑话
        请求地址:https://autumnfish.cn/api/user/reg
        请求方式:post
        请求参数:username(用户名,字符串)
        响应内容:注册成功或者失败
        */
    // 绑定事件到post请求按钮上
    document.querySelector(".post").onclick = function () {
        axios.post("https://autumnfish.cn/api/user/reg",{username:"莱维"})
            .then(function(response){
            console.log(response);
        }),function(err){
            console.log(err);
        }
    }
</script>

image-20211114180912558

axios的基本使用

axois与Vue结合

上面简单的举了下axios中get和post请求的应用例子,接下来我们就使用axios+vue来开发一个简单网络应用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DGFpegE1-1650422248959)(https://gitee.com/AuroraLeVi/markdown/raw/master/img/axois%E4%B8%8EVue%E7%BB%93%E5%90%88.png)]

网络应用的核心,就是定义在data的数据一部分是通过网络获取到的,故我们在方法中发送网络请求,再把服务器响应后返回的数据设置到data中对应的值。

导入vue和axios,这两个引入的先后顺序无所谓,但是一定要保证在开始写vue代码之前引入。
使用v-on绑定click事件,在p标签中显示获取的笑话内容。
在vue中写获取笑话的逻辑,即使用axios.get().then()方法获取随机笑话。

下面是要用到的接口:

/*
        接口:随机获取一条笑话
        请求地址:https://autumnfish.cn/api/joke
        请求方式:get
        请求参数:无
        响应内容:一条随机的笑话
*/

注意:这个笑话接口请求的笑话是在data里面!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MuNyBqnP-1650422248966)(D:\Typera_Image\image-20211114195713553.png)]

所以,应该写成response.data而不是response

<div id="app">
    <input type="button" value="随机获取笑话" @click="getJoke">
    <p v-cloak>
        {{ joke }}
    </p>
</div>
<!--axios官网提供的在线地址-->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
    /*
        接口:随机获取一条笑话
        请求地址:https://autumnfish.cn/api/joke
        请求方式:get
        请求参数:无
        响应内容:一条随机的笑话
        */
    var app = new Vue({
        el: "#app",
        data: {
            joke:"很好笑的笑话"
        },
        methods: {
            getJoke:function(){
                console.log(this.joke);
                // 绑定点击事件到get请求按钮上
                axios.get("https://autumnfish.cn/api/joke").then(function(response){
                    // console.log(response);
                    console.log(response.data);
                    console.log(this.joke);
                },function(err){
                    console.log(err);
                }
                                                                )
            }
        }
    })
</script>

image-20211114200737205

欸???console中明明已经拿到数据了呀,为什么页面没有更新?

注意,axios回调函数中的this已经改变,无法访问到data中的数据。通常的做法是,在进入回调函数作用域之前将this保存起来,回调函数中使用保存好的this(比如:var that = this;)即可。

这是因为axios回调函数中的this已经改变,无法访问到data中的数据。

解决方法:把this保存起来,回到函数中直接使用保存的this即可。

axios回调函数中的this已经改变,无法访问到data中的数据。
解决方法:把this保存起来,回调函数中直接使用保存的this即可。
和本地应用的最大区别就是改变了数据来源。

天知道

Vue+Axios开发一个查询天气的应用。

在输入框输入城市名字后点搜索或按回车键后,在下方会显示出所输入城市的天气预报,或者是鼠标点击输入框下方的热门城市,也可获取相应热门城市的天气预报。

回车查询

回车查询

HTML代码
<!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>axios+vue天知道</title>
        <link rel="stylesheet" href="css/indexstyle.css" />
        <link rel="stylesheet" href="css/reset.css" />
    </head>

    <body>

        <div class="wrap" id="app">
            <div class="search_form">
                <div class="logo"><img src="../img/t-logo.png" alt="logo" /></div>
                <div class="form_group">
                    <input type="text" class="input_txt" placeholder="请输入查询的天气" v-model="city"
                           @keyup.enter="searchWeather" />
                    <button class="input_sub">
                        搜 索
                    </button>
                </div>
                <div class="hotkey">
                    <a href="javascript:;" @click="queryWeather('北京')">北京</a>
                    <a href="javascript:;" @click="queryWeather('上海')">上海</a>
                    <a href="javascript:;" @click="queryWeather('广州')">广州</a>
                    <a href="javascript:;" @click="queryWeather('深圳')">深圳</a>
                </div>
            </div>
            <ul class="weather_list">
                <li v-for="item in weatherList">
                    <div class="info_type"><span class="iconfont">{{ item.type }}</span></div>
                    <div class="info_temp">
                        <b>{{ item.low }}</b>
                        ~
                        <b>{{ item.high }}</b>
                    </div>
                    <div class="info_date"><span>{{ item.date }}</span></div>
                </li>
            </ul>
        </div>
        <!-- 开发环境版本,包含了有帮助的命令行警告 -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <!-- 官网提供的 axios 在线地址 -->
        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
        <!-- 自己的js,逻辑代码建议写在单独的js文件中-->
        <script src="./js/main.js"></script>

    </body>

</html>
Vue.js代码
/*
  请求地址:http://wthrcdn.etouch.cn/weather_mini
  请求方法:get
  请求参数:city(城市名)
  响应内容:天气信息
    1. 点击回车
    2. 查询数据
    3. 渲染数据
*/

var app = new Vue({
    el: "#app",
    data: {
        city:'',
        weatherList:[]
    },
    methods: {
        searchWeather:function(){
            // console.log('天气查询');
            // console.log(this.city);
            // 在回调函数写代码记得保存this
            // this本身是指向data这个对象的,但是由于回掉函数存在嵌套,会改变this指向为undefined,所以要在未嵌套之前保存this指向
            var that = this;
            // 调用接口
            axios.get("http://wthrcdn.etouch.cn/weather_mini?city="+this.city)
                .then(function(response){
                // console.log(response);
                // console.log(response.data.data.forecast);
                // response.data.data.forecast是什么意思呢?访问接口的时候,我们真正所需要的数据被一层一层的包裹
                // response.data.data.forecast拿到的就是服务器返回给我们的关于天气的信息
                that.weatherList = response.data.data.forecast;
            },function(err){
                console.log(err);
            }
                     )
        }
    }
})

关于response.data.data.forecast; 为什么通过这个可以访问到天气数据呢?

我们访问接口的时候,我们真正所需要的数据被一层一层的包裹,console.log() 将response输出到控制台,我们就能看到数据所在的位置,从而进行访问获取。

image-20211114211434799

image-20211114211114453

应用的逻辑代码建议和页面分离,使用单独的js文件编写。
axios回调函数中this指向改变了,需要额外的保存一份。
服务器返回的数据比较复杂时,获取的时候需要注意层级结构。

点击查询

天知道-点击查询

html代码
<!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>axios+vue天知道</title>
        <link rel="stylesheet" href="css/indexstyle.css" />
        <link rel="stylesheet" href="css/reset.css" />
    </head>

    <body>

        <div class="wrap" id="app">
            <div class="search_form">
                <div class="logo"><img src="../img/t-logo.png" alt="logo" /></div>
                <div class="form_group">
                    <input type="text" class="input_txt" placeholder="请输入查询的天气" v-model="city"
                           @keyup.enter="searchWeather" />
                    <button class="input_sub" @click="searchWeather">
                        搜 索
                    </button>
                </div>
                <div class="hotkey">
                    <a href="javascript:;" @click="changeCity('重庆')">重庆</a>
                    <a href="javascript:;" @click="changeCity('上海')">上海</a>
                    <a href="javascript:;" @click="changeCity('广州')">广州</a>
                    <a href="javascript:;" @click="changeCity('成都')">成都</a>
                </div>
            </div>
            <ul class="weather_list">
                <li v-for="item in weatherList">
                    <div class="info_type"><span class="iconfont">{{ item.type }}</span></div>
                    <div class="info_temp">
                        <b>{{ item.low }}</b>
                        ~
                        <b>{{ item.high }}</b>
                    </div>
                    <div class="info_date"><span>{{ item.date }}</span></div>
                </li>
            </ul>
        </div>
        <!-- 开发环境版本,包含了有帮助的命令行警告 -->
        <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
        <!-- 官网提供的 axios 在线地址 -->
        <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
        <!-- 自己的js,逻辑代码建议写在单独的js文件中-->
        <script src="./js/main.js"></script>

    </body>

</html>
Vue.js代码
/*
  请求地址:http://wthrcdn.etouch.cn/weather_mini
  请求方法:get
  请求参数:city(城市名)
  响应内容:天气信息
    1. 点击回车
    2. 查询数据
    3. 渲染数据
*/

var app = new Vue({
    el: "#app",
    data: {
        city:'',
        weatherList:[]
    },
    methods: {
        searchWeather:function(){
            // console.log('天气查询');
            // console.log(this.city);
            // 在回调函数写代码记得保存this
            // this本身是指向data这个对象的,但是由于回掉函数存在嵌套,会改变this指向为undefined,所以要在未嵌套之前保存this指向
            var that = this;
            // 调用接口
            axios.get("http://wthrcdn.etouch.cn/weather_mini?city="+this.city)
                .then(function(response){
                // console.log(response);
                // console.log(response.data.data.forecast);
                // response.data.data.forecast是什么意思呢?访问接口的时候,我们真正所需要的数据被一层一层的包裹
                // response.data.data.forecast拿到的就是服务器返回给我们的关于天气的信息
                that.weatherList = response.data.data.forecast;
            },function(err){
                console.log(err);
            }
                     )
        },
        changeCity:function(city){
            this.city = city;
            // methods中定义的方法内部,可以通过this关键字点出其他方法
            this.searchWeather();
        }
    }
})

image-20211114213225985

自定义函数可以让代码复用性更高。
methods中定义的方法内部,可以通过this关键字点出其他方法。

综合应用

1.歌曲搜索

2.歌曲播放(点击按钮播放)

3.歌曲封面

4.歌曲评论

5.播放动画

6.mv播放

综合应用-悦听

最后的 mv 关闭遮罩,音频还在播放的解决办法。亲测好用~

hide: function () {
    this.isShow = false;
    this.mvUrl =;
}
el: "#player",
    data: {
        //歌曲名称
        musicName: "",
        //歌曲列表
        musicList: [],
        //歌曲地址
        musicUrl: "",
        //歌曲封面
        musicCover: "",
        //热门评论
        hotCommentList: [],
        //歌曲MV
        mvUrl: "",
        //封面状态
        isPlaying: false,
        // 遮罩层状态
        isShow: false
    }
音乐查询
  1. 按下回车(v-on .enter)
  2. 查询数据(axios 接口 v-model )
  3. 渲染数据(v-for 数组 that)

综合应用-歌曲搜索

HTML

<!-- 搜索歌曲 -->
<input type="text" autocomplete="off" v-model="musicName" @keyup.enter="searchMusic" />
<!--......-->
<!-- 搜索歌曲列表 -->
<div class='song_wrapper'>
    <ul class="song_list">
        <li v-for="item in musicList">
            <a href="javascript:;" @click="playMusic(item.id)"></a>
            <b>{{item.name}}</b>
            <span><i @click="getMV(item.mvid)" v-if="item.mvid!=0"></i></span>
        </li>
    </ul>
    <img src="../img/line1.png" class="switch_btn" alt="">
</div>

JS

//搜索歌曲
searchMusic: function () {
    var that = this;
    axios.get("https://autumnfish.cn/search?keywords=" + this.musicName)
        .then(function (response) {
        //console.log(response.data.result.songs)
        that.musicList = response.data.result.songs;
        // console.log(response.data.result.songs);
    }, function (err) {
        console.log(err);
    })
}

歌曲搜索

歌曲播放
1. 点击播放(v-on 自定义参数)

点击播放按钮:播放歌曲的本质就是设置歌曲的src,切换歌曲就是更换不同的src,歌曲的地址从network查看,歌曲地址是通过接口获取到的,获取歌曲地址后找到歌曲播放地址,将播放地址存到data的musicUrl字段中,再传给给audio标签; 注:点击时需要传入参数,从接口获得的歌曲的点击事件才会才会被绑定。

2. 歌曲地址获取

根据接口确定一个传递的参数(歌曲id),搜索出的歌曲时服务器返回的结果数组中每一项都有歌曲id,不同歌曲id不同,但查询逻辑是一样的;(总:接口调用,把所需的参数传过去)

3. 歌曲地址设置(v-bind)

data中增加歌曲属性,歌曲id依赖与歌曲的搜索结果,v-bind绑定到播放条中。
综合应用-歌曲播放

HTML

<div class="audio_con">
    <audio ref='audio' @play="play" @pause="pause" :src="musicUrl" controls autoplay loop
           class="myaudio"></audio>
</div>

JS

//播放歌曲
playMusic: function (musicId) {
    var that = this;
    axios.get("https://autumnfish.cn/song/url?id=" + musicId)
        .then(function (response) {
        console.log(response);
        // 这里获取的url(response.data.data.url)要求网易云音乐验证
        console.log("歌曲id: " + response.data.data.url)
        that.musicUrl = response.data.data.url;
    }, function (err) {
        console.log(err);
    })

歌曲播放

歌曲封面

综合应用-歌曲封面

HTML

<!-- 歌曲封面 -->
<img :src="musicCover" class="cover autoRotate" />

JS

//歌曲封面
axios.get("https://autumnfish.cn/song/detail?ids=" + musicId)
    .then(function (response) {
    // 这里遇到的问题是 https://autumnfish.cn/song/detail?ids= 404
    // console.log(response);
    // console.log(response.data.songs[0].al.picUrl)
    that.musicCover = response.data.songs[0].al.picUrl;
}, function (err) { 
    console.log(err);
})

歌曲封面

歌曲评论

综合应用-歌曲评论

HTML

<div class='comment_list'>
    <dl v-for="item in hotCommentList">
        <dt><img :src="item.user.avatarUrl" alt="评论角色图片"></dt>
        <!-- 评论角色昵称 -->
        <dd class="name">{{item.user.nickname}}</dd>
        <!-- 评论角色评论内容 -->
        <dd class="detail">
            {{item.content}}
        </dd>
    </dl>
</div>

JS

//热门评论
axios.get("https://autumnfish.cn/comment/hot?type=0&id=" + musicId)
    .then(function (response) {
    // console.log(response);
    //console.log(response.data.hotComments)
    that.hotCommentList = response.data.hotComments;
}, function (err) {
    console.log(err);
})

歌曲评论

播放动画
  1. 监听音乐播放(v-on play)
    核心:增删一个类。播放时碟片旋转,暂停时停止旋转,检测动画的播放状态,在对应的事件中增删类名。

注意:playing class 是模板css的动画效果,绑上就转。

music.css

body,
ul,
dl,
dd {
    margin: 0px;
    padding: 0px;
}

.wrap {
    position: fixed;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background: url("/img/bg.jpg") no-repeat;
    background-size: 100% 100%;
}

.play_wrap {
    width: 800px;
    height: 544px;
    position: fixed;
    left: 50%;
    top: 50%;
    margin-left: -400px;
    margin-top: -272px;
    /* background-color: #f9f9f9; */
}

.search_bar {
    height: 60px;
    background-color: #1eacda;
    border-top-left-radius: 4px;
    border-top-right-radius: 4px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    position: relative;
    z-index: 11;
}

.search_bar img {
    margin-left: 23px;
}

.search_bar input {
    margin-right: 23px;
    width: 296px;
    height: 34px;
    border-radius: 17px;
    border: 0px;
    background: url("/img/zoom.png") 265px center no-repeat rgba(255, 255, 255, 0.45);
    text-indent: 15px;
    outline: none;
}

.center_con {
    height: 435px;
    background-color: rgba(255, 255, 255, 0.5);
    display: flex;
    position: relative;
}

.song_wrapper {
    width: 200px;
    height: 435px;
    box-sizing: border-box;
    padding: 10px;
    list-style: none;
    position: absolute;
    left: 0px;
    top: 0px;
    z-index: 1;
}

.song_stretch {
    width: 600px;
}

.song_list {
    width: 100%;
    overflow-y: auto;
    overflow-x: hidden;
    height: 100%;
}

.song_list::-webkit-scrollbar {
    display: none;
}

.song_list li {
    font-size: 12px;
    color: #333;
    height: 40px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    width: 580px;
    padding-left: 10px;
}

.song_list li:nth-child(odd) {
    background-color: rgba(240, 240, 240, 0.3);
}

.song_list li a {
    display: block;
    width: 17px;
    height: 17px;
    background-image: url("/img/play.png");
    background-size: 100%;
    margin-right: 5px;
    box-sizing: border-box;
}

.song_list li b {
    font-weight: normal;
    width: 122px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.song_stretch .song_list li b {
    width: 200px;
}

.song_stretch .song_list li em {
    width: 150px;
}

.song_list li span {
    width: 23px;
    height: 17px;
    margin-right: 50px;
}

.song_list li span i {
    display: block;
    width: 100%;
    height: 100%;
    cursor: pointer;
    background: url("/img/table.png") left -48px no-repeat;
}

.song_list li em,
.song_list li i {
    font-style: normal;
    width: 100px;
}

.player_con {
    width: 400px;
    height: 435px;
    position: absolute;
    left: 200px;
    top: 0px;
}

.player_con2 {
    width: 400px;
    height: 435px;
    position: absolute;
    left: 200px;
    top: 0px;
}

.player_con2 video {
    position: absolute;
    left: 20px;
    top: 30px;
    width: 355px;
    height: 265px;
}

.disc {
    position: absolute;
    left: 73px;
    top: 60px;
    z-index: 9;
}

.cover {
    position: absolute;
    left: 125px;
    top: 112px;
    width: 150px;
    height: 150px;
    border-radius: 75px;
    z-index: 8;
}

.comment_wrapper {
    width: 180px;
    height: 435px;
    list-style: none;
    position: absolute;
    left: 600px;
    top: 0px;
    padding: 25px 10px;
}

.comment_wrapper .title {
    position: absolute;
    top: 0;
    margin-top: 10px;
}

.comment_wrapper .comment_list {
    overflow: auto;
    height: 410px;
}

.comment_wrapper .comment_list::-webkit-scrollbar {
    display: none;
}

.comment_wrapper dl {
    padding-top: 10px;
    padding-left: 55px;
    position: relative;
    margin-bottom: 20px;
}

.comment_wrapper dt {
    position: absolute;
    left: 4px;
    top: 10px;
}

.comment_wrapper dt img {
    width: 40px;
    height: 40px;
    border-radius: 20px;
}

.comment_wrapper dd {
    font-size: 12px;
}

.comment_wrapper .name {
    font-weight: bold;
    color: #333;
    padding-top: 5px;
}

.comment_wrapper .detail {
    color: #666;
    margin-top: 5px;
    line-height: 18px;
}

.audio_con {
    height: 50px;
    background-color: #f1f3f4;
    border-bottom-left-radius: 4px;
    border-bottom-right-radius: 4px;
}

.myaudio {
    width: 800px;
    height: 40px;
    margin-top: 5px;
    outline: none;
    background-color: #f1f3f4;
}

/* 旋转的动画 */
@keyframes Rotate {
    from {
        transform: rotateZ(0);
    }

    to {
        transform: rotateZ(360deg);
    }
}

/* 旋转的类名 */
.autoRotate {
    animation-name: Rotate;
    animation-iteration-count: infinite;
    animation-play-state: paused;
    animation-timing-function: linear;
    animation-duration: 5s;
}

/* 是否正在播放 */
.player_con.playing .disc,
.player_con.playing .cover {
    animation-play-state: running;
}

.play_bar {
    position: absolute;
    left: 200px;
    top: -10px;
    z-index: 10;
    transform: rotate(-25deg);
    transform-origin: 12px 12px;
    transition: 1s;
}

/* 播放杆 转回去 */
.player_con.playing .play_bar {
    transform: rotate(0);
}

/* 搜索历史列表 */
.search_history {
    position: absolute;
    width: 296px;
    overflow: hidden;
    background-color: rgba(255, 255, 255, 0.3);
    list-style: none;
    right: 23px;
    top: 50px;
    box-sizing: border-box;
    padding: 10px 20px;
    border-radius: 17px;
}

.search_history li {
    line-height: 24px;
    font-size: 12px;
    cursor: pointer;
}

.switch_btn {
    position: absolute;
    right: 0;
    top: 0;
    cursor: pointer;
}

.right_line {
    position: absolute;
    left: 0;
    top: 0;
}

.video_con video {
    position: fixed;
    width: 800px;
    height: 546px;
    left: 50%;
    top: 50%;
    margin-top: -273px;
    transform: translateX(-50%);
    z-index: 990;
}

.video_con .mask {
    position: fixed;
    width: 100%;
    height: 100%;
    left: 0;
    top: 0;
    z-index: 980;
    background-color: rgba(0, 0, 0, 0.8);
}

.video_con .shutoff {
    position: fixed;
    width: 40px;
    height: 40px;
    background: url("/img/shutoff.png") no-repeat;
    left: 50%;
    margin-left: 400px;
    margin-top: -273px;
    top: 50%;
    z-index: 995;
}
  1. 监听音乐暂停(v-on pause)

  2. 操纵类名(v-bind 对象)
    audio标签的play事件会在音频播放的时候触发 audio 标签的pause事件会在音频暂停的时候触发,通过对象的方式设置类名,类名生效与否取决于后面值的真假。

综合应用-播放动画

HTML

<!-- 歌曲信息容器 -->
<div class="player_con" :class="{playing:isPlaying}">
	......
</div>

JS

// 歌曲播放
play: function () {
    // console.log("play");
    this.isPlaying = true;
},
    // 歌曲暂停
    pause: function () {
        // console.log("pause");
        this.isPlaying = false;
    },

综合应用-播放动画

mv播放

综合应用-MV播放

HTML

<div class="video_con" style="display: none;" v-show="isShow">
    <video controls="controls" :src="mvUrl"></video>
    <!-- mask遮罩层 -->
    <div class="mask" @click="hide"></div>
</div>

JS

// 播放mv
getMV: function (mvid) {
    var that = this;
    axios.get("https://autumnfish.cn/mv/url?id=" + mvid).then(
        function (response) {
            // console.log(response);
            // console.log("MV url" + response.data.data.url);
            that.isShow = true;
            that.mvUrl = response.data.data.url;
        },
        function (err) { 
            console.log(err);
        }
    );
},
    // 隐藏
    hide: function () {
        this.isShow = false;
    }

播放mv

脚手架快速搭建vue项目

本例环境

由于vue的安装与创建依赖node.js(JavaScript的运行环境)里的npm(包管理和分发工具),因此需要先确保安装node.js。

npm会随着node.js一起安装,所以,只要是node.js正常安装,就代表npm已经安装

安装vue脚手架:npm install -g @vue/cli

使用淘宝镜像来安装:npm install -g @vue/cli --registry=https://registry.npm.taobao.org

node -v
 v16.13.1
npm -v
 8.1.2
vue -V
 @vue/cli 4.5.15

使用 vue-cli 搭建脚手架

Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统,基于 webpack 构建,并带有合理的默认配置;Vue CLI 将 Vue 生态中的工具基础标准化。而不必纠结配置的问题。

  1. 交互式的项目脚手架。

  2. 实现的零配置原型开发。

新版脚手架安装完成之后,我们要检查一下webpack是否已经安装,如果没有安装,我们要使用cnpm install webpack -g命令来安装webpack

首先我们在电脑的合适位置新建一个文件夹,然后使用cd命令来到这个文件夹:

首先我们在电脑的合适位置新建一个文件夹,然后使用cd命令来到这个文件夹

在这里我们可以输入vue create 项目名称命令来创建我们的Vue项目,比如这里我要创建一个名为ant-design-vue的项目。

输入vue create ant-design-vue命令之后,窗口会提示我们是否要安装一些默认组件,我们这里不需要默认安装,选择第二个【Manually select features】,可以进行自定义选择要安装的组件,通过空格键选择要安装的组件,然后回车继续下面的选项

vue cli自动搭建vue项目脚手架-选择第二个【Manually select features】,可以进行自定义选择要安装的组件,通过空格键选择要安装的组件,然后回车继续下面的选项

可以按照自己的需要选择要加入的组件

Vue Cli选项

Choose Vue version 选择版本,我选的2.x

vue+Ant design vue

使用 npm 或 yarn 安装ant-design-vue

npm install ant-design-vue --save

在main.js中引用

import Vue from 'vue';

import Antd from 'ant-design-vue'// 引入Ant Design Vue组件
import 'ant-design-vue/dist/antd.css' // 引入Ant Design Vue样式
Vue.use(Antd) // 挂载到vue中
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值