vue

发布时间 2024-01-07 22:02:35作者: PursueExcellence

概述

Vue概述

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

vue遵循soc原则

SOC原则:关注点分离原则

前端知识体系

想要成为真正的“互联网Java全栈工程师”还有很长的一段路要走,其中“我大前端”是绕不开的一门必修课。本阶段课程的主要目的就是带领我Java后台程序员认识前端、了解前端、掌握前端,为实现成为“互联网Java全栈工程师”再向前迈进一步。

前端三要素

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

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

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

表现层(CSS)

CSS层叠样式表是一门标记语言,不是编程语言,因此不能自定义变量,不能引用等,换句话说就是不具备任何语法支持

它主要缺陷如下:

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

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

CSS预处理器

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

**常用的CSS预处理器: **

  • SASS :基于Ruby,通过服务端处理,功能强大。解析效率高。需要学习Ruby语言,上手难度高于LESS。
  • **LESS ** :基于NodeJS,通过客户端处理,使用简单。功能比SASS简单,解析效率也低于SASS,但在实际开发中足够了,所以我们后台人员如果需要的话,建议使用LESS。

行为层(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)才能被浏览器正确执行。

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

UI框架

Ant-Design

阿里巴巴出品,基于React的UI框架

ElementUI、 iview、 ice

饿了么出品,基于Vue的UI框架

Bootstrap

Twitter推出的一个用于前端开发的开源工具包

AmazeUI

又叫"妹子UI",一款HTML5跨屏前端框架.

JavaScript 构建工具

Babel

JS编译工具,主要用于浏览器不支持的ES新特性,比如用于编译TypeScript

WebPack

模块打包器,主要作用是打包、压缩、合并及按序加载

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

三端合一

混合开发(Hybid App)

主要目的是实现一套代码三端统一(PC、Android:.apk、iOS:.ipa )并能备够调用到底层件(如:传感器、GPS、 摄像头等),

打包方式主要有以下两种:

  • 云打包: HBuild -> HBuildX, DCloud出品; API Cloud
  • 本地打包: Cordova (前身是PhoneGap)

后端技术

前端人员为了方便开发也需要掌握一定的后端技术, 但我们Java后台人员知道后台知识体系极其庞大复杂,所以为了方便前端人员开发后台应用,就出现了NodeJS这样的技术。

NodeJS的作者已经声称放弃NodeJS (说是架构做的不好再加上笨重的node_ modules,可能让作者不爽了吧),开始开发全新架构的Deno

既然是后台技术,那肯定也需要框架和项目管理工具,NodeJS 框架及项目管理工具如下:

  • Express: NodeJS框架
  • Koa: Express简化版
  • NPM:项目综合管理工具,类似于Maven
  • YARN: NPM的替代方案,类似于Maven和Gradle的关系

MVVM

什么是MVVM

MVVM (Model-View-ViewModel) 是一种软件架构设计模式,由微软WPF (用于替代WinForm,以前就是用这个技术开发桌面应用程序的)和Silverlight (类似于Java Applet,简单点说就是在浏览器上运行的WPF)的架构师Ken Cooper和Ted Peters 开发,是一种简化用户界面的事件驱动编程方式。由John Gossman (同样也是WPF和Silverlight的架构师)于2005年在他的博客上发表。
MVVM 源自于经典的 MVC (ModI-View-Controller) 模式。MVVM的核心是ViewModel层,负责转换Model中的数据对象来让数据变得更容易管理和使用,其作用如下:

  • 该层向上与视图层进行双向数据绑定
  • 向下与Model层通过接口请求进行数据交互

image-20230816180630408

为什么要使用MVVM

MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大好处:

  • 低耦合:视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
  • 可复用:你可以把一些视图逻辑放在一个ViewModel里面,让很多View重用这段视图逻辑。
  • 独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计。、
  • 可测试:界面素来是比较难于测试的,而现在测试可以针对ViewModel来写。

Vue 是 MVVM 模式的实现者

202308161809

Model : 模型层,在这里表示JavaScript对象

View : 视图层,在这里表示DOM (HTML操作的元素)

ViewModel : 连接视图和数据的中间件,Vue.js就是MVVM中的ViewModel层的实现者,在MVVM架构中,是不允许数据和视图直接通信的,只能通过ViewModel来通信,而ViewModel就是定义了一个Observer观察者

ViewModel 能够观察到数据的变化,并对视图对应的内容进行更新

ViewModel 能够监听到视图的变化,并能够通知数据发生改变

Vue.js 就是一个MVVM的实现者,他的核心就是实现了DOM监听数据绑定

第一个 Vue 程序

Vue不支持IE8以及以下版本,因为Vue使用了IE8无法模拟的ECMAScript5的特性,但它支持所有兼容ECMAScript5的浏览器

下载地址

开发版本

包含完整的警告和调试模式:https://vue.js.org/js/vue.js

删除了警告,30.96KB min + gzip:https://vue.js.org/js/vue.min.js

CDN

https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js

https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js

引用vue的cdn地址有很多,如果以上的地址无法引用时,可以查询别的cdn

实现步骤

IDEA安装Vue插件

image-20230817150230421

创建工程

image-20230817155836696

代码编写

demo1.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--View 层-->
<div id="app">
    <!--4、元素获取 vue 中的数据-->
    {{message}}
</div>

<!--1、导入 vue.js -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.min.js"></script>
<script>
    var vm = new Vue({
        // 2、绑定 app 元素
        el: "#app",
        // Model 层
        // 3、插入数据,键值对
        data: {
            message: "hello,vue"
        }
    });
</script>
</body>
</html>

测试

直接打开浏览器,运行测试

image-20230817160113041

打开开发者工具,选择 Console输入 ,并回车

image-20230817160219688

发现页面的数据也变了,这就是 ViewModel 双向绑定

view层的数据 和 message 这个变量绑定,message 改变页面上的数据也改变了

Vue基本语法

代码示例

demo2.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<!--View 层-->
<div id="app">
  <!--4、元素获取 vue 中的数据-->
  <!--{{message}}-->
  <span v-bind:title="message">
        鼠标悬停几秒可查看绑定的信息
      </span>
</div>
<!--1、导入 vue.js -->
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.min.js"></script>
<script>
  var vm = new Vue({
    // 2、绑定 app 元素
    el: "#app",
    // Model 层
    // 3、插入数据,键值对
    data: {
      message: "hello,vue"
    }
  });
</script>
</body>
</html>

通过浏览器运行页面查看

image-20230817162556780

发现 使用 v-bind: 也可以把变量绑定到元素上

概述

你看到的v-bind被称作指令,指令带有前缀v-,以表示他们时Vue提供的特殊性,可能你已经猜到了,他们会在渲染的DOM上应用特殊的响应式方式。

v-if

demo3.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <!--if-else-->
    <span v-if="ok">Yes</span>
    <span v-else>No</span>
</div>

<script src="https://cdn.bootcss.com/vue/2.5.21/vue.min.js"></script>
<script>

    var vm = new Vue({
        el: "#app",
        data: {
             ok:true
        }
    });

</script>

</body>
</html>

测试结果:

image-20230817164546210

image-20230817164631555

v-else-if

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">

    <!--if-else if-else-->
    <span v-if="message==='A'">A</span>
    <span v-else-if="message==='B'">B</span>
    <span v-else-if="message==='C'">C</span>
    <span v-else>D</span>

</div>

<script src="https://cdn.bootcss.com/vue/2.5.21/vue.min.js"></script>
<script>

    var vm = new Vue({
        el: "#app",
        data: {
            message:"A"
        }
    });

</script>

</body>
</html>

测试结果:

image-20230817164706672

image-20230817164811257

for

demo4.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id = "app">
    <!--类似于java 的 foreach,从 items 中遍历出的每一项命名为 item-->
    <li v-for="item in items">{{item.message}}</li>
</div>

<script src="https://cdn.bootcss.com/vue/2.5.21/vue.min.js"></script>
<script>
    var vm = new Vue({
        el:"#app",
        data:{
            items:[
                {message:"java"},
                {message:"html"},
                {message:"css"},
                {message:"js"}
            ]
        }
    });
</script>

</body>
</html>

image-20230817165552101

监听事件

可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。

demo5.html

<div id="app">
  <button v-on:click="sayHi()">click me</button>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.min.js"></script>
<script>
  var vm = new Vue({
    el: "#app",
    data: {
      message: "Hi!!!"
    },
    // 定义方法
    // 注意一定要加 s
    methods: {
      // 冒号前是方法名
      sayHi: function (){
        alert(this.message);
      }
    }
  });
</script>

image-20230817170413001

双向绑定

什么是数据双向绑定

vue是一个mvvm框架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。这也算是vue的精髓之处了。

值得注意的是,我们所说的数据双向绑定,一定是对于UI控件来说的,非UI控件不会涉及到数据双向绑定。 单向数据绑定是使用状态管理工具(如redux)的前提。如果我们使用vuex,那么数据流也是单项的,这时就会和双向数据绑定有冲突,我们可以这么解决

为什么要实现数据的双向绑定

在vue中,如果使用vuex,实际上数据还是单向的,之所以说是数据双向绑定,这是用的UI控件来说,对于我们处理表单,vue的双向数据绑定用起来就特别舒服了。

即两者并不互斥, 在全局性数据流使用单项,方便跟踪; 局部性数据流使用双向,简单易操作。

表单中使用双向数据绑定

可以用 v-model 指令在表单 < input >、< textarea > 及 < select > 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。

注意:v-model会忽略所有表单元素的value,checked,selected特性的初始值而总是将Vue实例的数据作为数据来源,你应该通过JavaScript在组件的data选项中声明初始值

使用

输入框

demo6.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <!--
      双向绑定:
        data 中的 message 既和输入框的 message 绑定
        又和 p 标签中的 message 绑定
    -->
    <span>输入文本:</span><input type="text" v-model="message">{{message}}
    <p><span>输入的文本:</span><span>{{message}}</span></p>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data: {
            message: ""
        }
    });
</script>
</body>
</html>

单选框

demo7.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    性别:
    <input type="radio" name="sex" value="male" v-model="sex"> 男
    <input type="radio" name="sex" value="female" v-model="sex"> 女

    <p>选中了:{{sex}}</p>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data: {
            sex: ""
        }
    });
</script>

</body>
</html>

image-20230817172105029

可以发现,这里绑定的是单选框的 Value

多选框

demo8.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
    <label for="jack">杰克</label>
    <input type="checkbox" id="john" value="John" v-model="checkedNames">
    <label for="john">约翰</label>
    <input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
    <label for="mike">麦克</label>
    <br>
    <span>Checked names: {{ checkedNames }}</span>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data: {
            checkedNames: []
        }
    });
</script>


</body>
</html>

image-20230817172403683

下拉框

demo9.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    下拉框:
    <select v-model="selected">
        <option value="" disabled>-请选择-</option>
        <option value="aaa">AA</option>
        <option value="bbb">BB</option>
        <option value="ccc">CC</option>
    </select>
    <p>选中 : {{selected}}</p>
</div>
<script src="https://cdn.bootcss.com/vue/2.5.21/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#app",
        data: {
            selected : ""
        }
    });
</script>
</body>
</html>

image-20230817172723034

组件

概述

组件是可复用的 Vue 实例,也就是在开发过程中可以把重复的部分封装为组件

组件的组织

image-20230817173250345

例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。

第一个组件demo

demo10.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="app">
    <!--v-bind 为自定义组件的jin属性赋值,值就是vm对象中定义的items数组的每一项的值-->
    <jinjiahuan v-for="item in items" v-bind:jin="item"></jinjiahuan>

</div>

<script src="https://cdn.bootcss.com/vue/2.5.21/vue.min.js"></script>
<script>

    // 自定义一个组件(其实就是定义一个标签)
    Vue.component("jinjiahuan",{
        // 可以理解为自定义组件(标签)的属性
        props:["jin"],
        // 自定义的jinjiahuan标签中包含了一个li标签,显示的信息就是自定义标签的jin属性值
        // 通过jin接收item的数据
        template:"<li>{{jin}}</li>"
    });

    var vm = new Vue({
        el:"#app",
        data:{
            items:["java","linux","前端"]
        }
    });

</script>
</body>
</html>

image-20230817180941563

Axios 异步通信

概述

Axios 是一个开源的可以用在浏览器端和 NodeJS 的异步通信框架,它的主要作用就是实现 AJAX 异步通信

功能特点:

  • 从浏览器中创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换 JSON 数据
  • 客户端支持防御 XSRF(跨站请求伪造)

为什么要使用 Axios

由于 Vue.js 是一个 视图层框架 并且作者(尤雨溪)严格准守 SoC (关注度分离原则),所以 Vue.js 并不包含 AJAX 的通信功能,Vue推荐使用 Axios 框架,尽量不适用 JQuery,因为它会频繁的操作DOM

前提

确认 IDEA 的 JavaScript 支持 ES6 规范

image-20230818135756623

地址

有些cdn地址请求不到,或者加载很慢,现尝试整理如下的地址

axios的cdn引用地址:

<script src="https://cdn.bootcss.com/vue/2.5.15/vue.min.js"></script>

<script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js"></script>

<script src="https://cdn.bootcss.com/axios/0.18.0/axios.min.js"></script>

<script src="https://cdn.bootcss.com/element-ui/2.4.9/index.js"></script>

<script src="https://cdn.bootcss.com/qs/6.5.2/qs.min.js"></script>

<script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js"></script>

第一个 Axios 应用程序

思路

1、因为在实际开发中,大多使用的是 JSON 格式数据,所以这里新建一个 JSON 格式的文件

2、编写 HTML - 获取 本地的 Json 数据

3、打开页面,打开开发者工具可以发现 Axios 和 AJax 一样是异步的通信

步骤

目录结构

image-20230818145723042

准备json数据

data.json

{
  "name": "呵呵",
  "url": "https://blog.csdn.net/weixin_44449838",
  "page": 123,
  "isNonProfit": true,
  "address": {
    "street": "塔克拉玛干沙漠",
    "city": "新疆",
    "country": "中国"
  },
  "links": [
    {
      "name": "Google",
      "url": "http://www.google.com"
    },
    {
      "name": "Baidu",
      "url": "http://www.baidu.com"
    }
  ]
}

编写代码

demo11.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <!--
        闪烁问题:刷新该页面,最先出现模板,然后才会渲染数据,这样看上去十分不友好
        下面的style能够解决闪烁问题
    -->
    <style>
        /*属性选择器*/
        [v-cloak]{
            display: none;
        }
    </style>

</head>
<body>

<div id="vue" v-clock>
    <!--    需要渲染的字段名 -->
    <div>{{info.name}}</div>
    <div>{{info.address}}</div>
    <div>{{info.address.city}}</div>
    <div v-for="link in info.links">
        <span>{{link.name}}</span>
        <a v-bind:href="link.url">{{link.url}}</a>
    </div>
</div>

<script src="https://cdn.bootcss.com/vue/2.5.21/vue.min.js"></script>
<!-- axios 的包-->
<script src="https://cdn.bootcss.com/axios/0.18.0/axios.min.js"></script>

<script>
    var vm = new Vue({
        el: "#vue",
        // 有冒号、大括号的 data 是属性
        data: {},
        // 没有冒号的是方法
        // 这里使用的 data 方法,不要搞混
        data() {
            return {
                // 请求的返回参数,这里需要写上需要返回的字段名,不需要写值,所以都写 null
                // 这里的键可以比传入的 Json 中的少
                // 但是如果写了,就必须和获得的 Json 键的名字一样
                info: {
                    name: null,
                    address: {
                        city: null,
                        country: null
                    },
                    links: [
                        {
                            name: null,
                            url: null
                        }
                    ]
                }
            }
        },
        // 钩子函数,在主流程执行过程中间执行的方法
        mounted() {
            // 这边把上面 return 中的 info 值和返回的 data 数据绑定,以便返回给视图渲染
            axios.get('./data.json').then(response => (this.info = response.data));
        }
    });
</script>
</body>
</html>

测试

image-20230818145810611

Vue 的生命周期

Vue 实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载 DOM、渲染 ->更新 ->渲染、卸载等一系列过程,这称为 Vue 的生命周期。

在 Vue 的整个生命周期中,它提供了一系列的事件,可以让我们在事件触发时注册 JS 方法,可以放我们自己注册的 JS 方法控制整个大局,在这些事件响应方法中的 this 直接指向的是 Vue 的实例。

202308181501

计算属性

计算属性,就是把计算出来的结果,保存在属性中

好处 :在内存中运行,虚拟 DOM

demo12.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="vue">
    <!-- 调用方法 -->
    <p>currentTime1 : {{currentTime1()}}</p>
    <!-- 调用属性 -->
    <p>currentTime2 : {{currentTime2}}</p>
</div>

<script src="https://cdn.bootcss.com/vue/2.5.21/vue.min.js"></script>
<script>
    var vm = new Vue({
        el: "#vue",
        data: {
            message: "hello."
        },
		
        // 定义的是普通方法
        methods: {
            currentTime1: function (){
                // 返回当前时间戳
                return Date.now();
            }
        },
		
        // 定义的是计算属性
        // 计算属性:methods 和 computed 方法名不能重名,重名之后,只会调用 methods 方法
        computed: {
            // 方法名不能一样
            currentTime2: function (){
                // 返回当前时间戳
                return Date.now();
            }
        }

    });
</script>

</body>
</html>

测试结果:

image-20230818152237603

调用

打开开发者工具

普通方法是调用方法名,所以调用的时候加上括号

image-20230818152905104

计算属性调用的是属性,并不是方法,所以调用的时候不加括号

image-20230818153056202

获取值的区别

普通方法调用一次,就会执行一次

image-20230818153436987

计算属性是将执行之后的结果存在在属性中(也就是内存),所以如果计算属性定义的方法中数据不改变,结果就不会变

image-20230818153612271

计算属性改变时机

计算属性定义的方法中,如果有数据改变,计算属性的值就会变

重新定义计算属性的方法

// 计算属性:methods 和 computed 方法名不能重名,重名之后,只会调用 methods 方法
computed: {
    // 方法名不能一样
    currentTime2: function (){
        let message = this.message;
        // 返回当前时间戳
        return Date.now();
    }
}

浏览器开发者选项测试

image-20230818154146819

内容分发— slot

插槽(slot) :动态可插拔的组件

案例实现

demo13.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="vue">
    <p>数据列表(原本的)</p>
    <ul>
        <li>java</li>
        <li>html</li>
        <li>css</li>
    </ul>
</div>

<hr/><br/>

<div id="app">
<!--
 1、绑定插槽:使用 slot 属性绑定插槽,属性值必须和下面的 name 属性值一样
 2、绑定数据:,v-bind指令可以简写为 :,:后面是自定义组件的属性名,组件的属性值绑定vue实例中data对应的属性的值
-->
    <list>
        <list-title slot="list-title" :title="title"></list-title>
        <list-items slot="list-items" v-for="item in items" :item="item"></list-items>
    </list>

</div>

<script src="https://cdn.bootcss.com/vue/2.5.21/vue.min.js"></script>
<script>
    Vue.component("list",{
        template:
            "<div>\
                <slot name='list-title'></slot>\
                <ul>\
                    <slot name='list-items'></slot>\
                </ul>\
            </div>"

    })

    Vue.component("list-title",{
        props:["title"],
        template: "<div>{{title}}</div>"
    })

    Vue.component("list-items",{
        props:["item"],
        template: "<li>{{item}}</li>"
    })

    var vm = new Vue({
        el: "#app",
        data:{
            title:"使用插槽",
            items:["java","html","js"]
        }
    });
</script>

</body>
</html>

image-20230818171240116

自定义事件内容分发

在上述案例的基础上,希望在每一行后面加一个删除按钮,且点击删除后删除该行

案例实现

思路:

  1. 视图层自定义一个事件,这个事件绑定到vue对象的方法,这个方法用来操作model数据
  2. 组件(插槽)通过 this.$emit() 方式绑定自定义事件,就可以将参数传递给自定义事件
  3. 通过视图层作为中介,最终就会实现组件可以操作model数据的效果

demo15.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<div id="vue">
    <p>数据列表(原本的)</p>
    <ul>
        <li>java</li>
        <li>html</li>
        <li>css</li>
    </ul>
</div>

<hr/><br/>

<div id="app">
    <!--
        1、绑定插槽:使用 slot 属性绑定插槽,属性值必须和下面的 name 属性值一样
        2、绑定数据:,v-bind指令可以简写为 :,:后面是自定义组件的属性名,组件的属性值绑定vue实例中data对应的属性的值
    -->
    <list>
        <list-title slot="list-title" :title="title"></list-title>
        <!-- : 号是 v-bind 指令的缩写-->
        <list-items slot="list-items" v-for="(index,item) in items" :item="item" :index="index"
        <!--自定义事件 jinjiahuan,绑定到vue对象的 removeItems 方法-->
        <!--自定义事件 jinjiahuan,绑定过到组件(插槽)中,通过 this.$emit() 方式-->
        v-on:jinjiahuan="removeItems(index)"></list-items>
    </list>

</div>

<script src="https://cdn.bootcss.com/vue/2.5.21/vue.min.js"></script>
<script>
    Vue.component("list",{
        template:
            "<div>\
                <slot name='list-title'></slot>\
                <ul>\
                    <slot name='list-items'></slot>\
                </ul>\
            </div>"

    })

    Vue.component("list-title",{
        props:["title"],
        template: "<div>{{title}}</div>"
    })

    Vue.component("list-items",{
        props:["item","index"],
        // v-on 指令可以简写为 @click ,只能绑定当前组件的方法
        template: "<li>{{item}}--{{index}}<button @click='remove(index)'>删除</button></li>",
        methods: {
            remove: function(index){
                // 绑定自定义事件
                this.$emit('jinjiahuan',index)
            }
        }
    })

    var vm = new Vue({
        el: "#app",
        data:{
            title:"使用插槽",
            items:["java","html","js"]
        },
        methods:{
            removeItems: function(index){
                console.log("删除了"+this.items[index]+"元素");
                // 删除当前下标的元素
                this.items.splice(index,1);
            }
        }
    });
</script>

</body>
</html>

结果测试:

image-20230823152826318

image-20230823152902900

Vue-cli

什么是vue-cli

vue-cli 官方提供的一个脚手架,用于快速生成一个 vue 的项目模板;

预先定义好的目录结构及基础代码,就好比咱们在创建 Maven 项目时可以选择创建一个骨架项目,这个骨架项目就是脚手架,我们的开发更加的快速;

主要功能:

  • 统一的目录结构
  • 本地调试
  • 热部署
  • 单元测试
  • 集成打包上线

需要的环境

安装 Node.js

1、此处使用node 12.13.0版本

https://registry.npmmirror.com/binary.html?path=node/v12.13.0/

image-20230823155722039

2、无脑下一步,安装完毕

image-20230823160309265

3、安装的时候如果没有默认配置环境变量,则需要手动进行配置

4、验证安装是否成功,cmd 下输入 node -v,查看是否能够正确打印出版本号即可!(建议使用管理员的身份)

安装加速器(cnpm)

安装 Node.js 淘宝镜像加速器(cnpm),这样子在话,下载就会快很多

// -g 就是全局安装
// 注意npm和cnpm版本的问题,这里使用的npm版本是 6.12.0,所以cnpm指定6.0.0版本安装
npm install -g cnpm@6.0.0

// 或者是在每次安装依赖的时候,指定安装地址,这样有点麻烦,不推荐使用
npm install --registry=https://registry.npm.taobao.org

image-20230823172800218

安装过程有点慢,耐心等待

image-20230823172830724

验证是否安装成功

image-20230823172920351

虽然安装了cnpm,但是尽量少用,如果npm命令下载失败的话,尝试使用cnpm

安装的位置: C:\Users\Lenovo\AppData\Roaming\npm\node_modules\cnpm\bin\cnpm

image-20230823162400350

安装vue-cli

cnpm install -g vue-cli 

image-20230823173057536

vue-cli安装位置:C:\Users\Lenovo\AppData\Roaming\npm\node_modules\vue-cli

image-20230823173146469

vue list

vue list 命令,可以看到能够创建什么样子的项目,类似于maven,安装了maven之后,可以创建普通的maven项目,也可以创建maven web 项目

image-20230823173534566

第一个Vue-cli 程序

创建项目目录

在指定的文件夹中使用cmd创建一个名为 myvue 的vue项目并用webpack打包工具打包

image-20230823174215473

初始化vue项目

在项目路径下进入到cmd窗口,初始化项目

// 初始化项目命令:创建一个名为 myvue的 webpack vue项目
vue init webpack myvue

image-20230823174531741

说明:
1、Project name:项目名称,默认 回车 即可
2、Project description:项目描述,默认 回车 即可
3、Author:项目作者,默认 回车 即可
4、Vue build :编译,选择第一个
5、Install vue-router:是否安装 vue-router,选择 n 不安装(后期需要再手动添加)
6、Use ESLint to lint your code:是否使用 ESLint 做代码检查,选择 n 不安装(后期需要再手动添加)
7、Set up unit tests:单元测试相关,选择 n 不安装(后期需要再手动添加)
8、Setup e2e tests with Nightwatch:单元测试相关,选择 n 不安装(后期需要再手动添加)
9、Should we run npm install for you after the project has been created:创建完成后直接初始化,选择 n,我们手动执行;运行结果!

创建完成之后,自定义目录中多了vue的项目

image-20230823174802813

安装依赖

// 进入文件夹
cd myvue
// 安装环境
npm install --registry=https://registry.npm.taobao.org
// 启动项目
npm run dev
// 停止 ctrl + c

image-20230823175504863

如果安装依赖的过程出现问题,按照提示,命令修复即可

image-20230823175711984

修复成功

image-20230823175734474

依赖安装完毕

启动项目

1、可以使用idea打开创建的myvue项目,看下目录结构

image-20230823180247123

2、启动项目

// 命令执行之后,会先打包,在运行
npm run dev

启动成功

image-20230823180440502

访问测试:

image-20230823180624659

停止项目

ctrl + c

image-20230823180709154

其他操作

在idea中使用终端运行vue项目

问题

image-20230823181753120

运行失败,非管理员身份运行会失败

解决

image-20230823182032069

Webpack

什么是webpack

webpack可以看做是静态模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式以供浏览器使用。

安装 Webpack

WebPack是一款模块加载器兼打包工具, 它能把各种资源, 如JS、JSX、ES 6、SASS、LESS、图片等都作为模块来处理和使用。

现在使用的node.js都是基于es6的规范,开发的时候也是面向es6开发的。但是现在的浏览器使用的是es5规范,所以不能正确运行自己开发的代码,需要用到Webpack将es6规范代码打包成为es5,供浏览器能够识别运行

安装命令

// 安装 Webpack
npm install webpack -g
// 安装Webpack客户端    
npm install webpack-cli -g

验证命令

验证是否安装成功

webpack -v
webpack-cli -v

配置

创建 webpack.config.js 配置文件

  • entry:入口文件, 指定Web Pack用哪个文件作为项目的入口
  • output:输出, 指定WebPack把处理完成的文件放置到指定路径
  • module:模块, 用于处理各种类型的文件
  • plugins:插件, 如:热更新、代码重用等
  • resolve:设置路径指向
  • watch:监听, 用于设置文件改动后直接打包(热部署)
module.exports = {
  entry:"",
    output:{
    path:"",
      filename:""
  },
  module:{
    loaders:[
      {test:/\.js$/,;\loade:""}
    ]
  },
  plugins:{},
  resolve:{},
  watch:true
}

直接运行 webpack 命令打包

使用webpack

项目结构

image-20230825161800723

创建项目

创建项目(其实就是创建一个文件夹),项目名为webpack-study,然后使用idea打开(idea接管这个项目)

创建modules目录

创建一个名为modules的目录,用于放置JS模块等资源文件。

创建模块文件

在modules目录下创建hello.js文件,hello.js用于编写JS模块相关代码

hello.js

// 暴露一个方法
exports.sayHi = function(){
  document.write("<h1>Hello World</h1>");
}

创建引入文件

在 modules 下创建一个名为 main.js 的入口文件,用于打包时设置entry属性

main.js

// 引入 hello.js,相当于java的对象
var hello = require("./hello");
// 调用 hello.js 中的方法
hello.sayHi();

创建webpack配置文件

在 webpack-study 目录下创建 webpack.config.js (注意是:点)配置文件,使用webpack命令打包

webpack.config.js

module.exports = {
    entry: './modules/main.js',
    output: {
        filename: "./js/bundle.js"
    }
}

使用 webpack 命令打包

image-20230825160847472

打包成功之后发现项目中多了一个dist目录,dist目录里面存在我们指定的打包输出文件

image-20230825161006449

在 HTML 页面中引入

在 webpack-study 目录下创建index.html文件,引入打包之后的bundle.js文件

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--前端的模块化开发-->
<script src="dist/js/bundle.js"></script>

</body>
</html>

在浏览器中运行

image-20230825161601125

vue-router

说明

Vue Router是Vue.js官方的路由管理器(路径跳转)。它和Vue.js的核心深度集成,让构建单页面应用变得易如反掌

包含的功能有:

  1. 嵌套的路由/视图表
  2. 模块化的、基于组件的路由配置
  3. 路由参数、查询、通配符
  4. 基于Vue.js过渡系统的视图过渡效果
  5. 细粒度的导航控制
  6. 带有自动激活的CSS class的链接
  7. HTML5历史模式或hash模式,在IE9中自动降级
  8. 自定义的滚动条行为

安装

按照第一个Vue-cli程序创建步骤在创建一个vue项目myvue2

cmd 进入 myvue2 目录,并执行

// 可以用
npm install vue-router --save-dev
// 如果没成功
cnpm install vue-router --save-dev

image-20230825165734502

安装完成之后在node_modules中查看是否引入了依赖

image-20230825165838650

获取纯净vue项目

删除vue的自带的文件,获取纯净项目

1、删除src/assets/logo.png图片文件

2、删除HelloWorld.vue文件

3、修改App.vue文件,删除关于使用HelloWorld.vue文件的组件和logo.png图片的地方

image-20230825170517177

通过上面的三个步骤就获取到了一个纯净的项目结构

使用

目录结构

创建自定义组件

Content.vue

<template>
  <h1>内容页</h1>
</template>

<script>

export default {
  name: "Content"
}

</script>

<!--scoped: 作用域,表示所加的样式只在当前文件有效-->
<style scoped>

</style>

配置路由

在 src 下新建一个包router

在该包中新建index.js文件,用来配置路由

index.js

// 导入vue
import Vue from 'vue';
// 导入vue-router
import VueRouter from "vue-router";
// 导入自定义组件Content
import Content from "../components/Content";
// 导入自定义组件Main
import Main from "../components/Main";

// 安装路由
Vue.use(VueRouter);

// 配置导出路由
export default new VueRouter({

  routes: [
    {
      // 路由路径
      path: '/content',
      name: 'content',
      // 跳转的组件
      component: Content
    },
    {
      // 路由路径
      path: '/main',
      name: 'main',
      // 跳转的组件
      component: Main
    }
  ]

});

使用路由

在main.js中使用路由

main.js

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
// 导入路由
// 自动扫描里面的路由配置。
// 这里只是定位到router文件夹,但是程序会找到下面的index.js路由配置文件
import router from './router'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  // 配置路由
  router,
  components: { App },
  template: '<App/>'
})

编写模板

在App.vue组件中编写模板

App.vue

<template>
  <div id="app">
    <router-link to="/main">首页</router-link>
    <router-link to="/content">内容页</router-link>
    <router-view></router-view>
  </div>
</template>

<script>

export default {
  name: 'App',
}

</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

测试结果:

image-20230829153835366

Vue+ElementUI

新建项目

新创建一个vue项目

vue init webpack vue-elementui

安装依赖

安装 vue-router、element-ui、sass-loader、node-sass 四个插件

# 进入工程
cd vue-elementui
# 安装 vue-router
npm install vue-router --save-dev 
# 安装 element-ui
npm i element-ui -S 
# 安装 SASS 加载器(注意node-sass版本和node版本的匹配问题)
cnpm install sass-loader --save-dev
cnpm install node-sass@4.12.0 --save-dev
# 安装依赖
npm install 
# 启动测试
npm run dev

测试报错:
cnpm install --save vue-hot-reload-api

命令解释:

  • npm install moduleName:安装模块到项目目录下
  • npm install -g moduleName:-g的意思是将模块安装到全局,具体安装到磁盘的那个位置,要看npm config perfix的位置
  • npm install --save moduleName:-save的意思是将模块安装到项目录下,并在packae文件的dependencies节点写入依赖,-S为该命令的缩写
  • npm install --save-dev moduleName:--save-dev的意思是将模块安装到项目目录下,并在package文件的devDependencies节点写入依赖,-D为该命令的缩写

获取纯净项目

把项目恢复为一个空项目

  • 删除 src 下的 logo.png、HelloWorld.vue,
  • 修改 App.vue如下
<template>
 </template>
 <script>
 export default {
   name: 'App'
 }
 </script>
 <style>
 #app {
   font-family: 'Avenir', Helvetica, Arial, sans-serif;
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
   text-align: center;
   color: #2c3e50;
   margin-top: 60px;
 }
 </style>

项目结构

新建router和views文件夹

image-20230829162154990

说明:

  • router存放路由信息
  • views:存放视图组件
  • components:存放功能性的组件

编写代码

目录结构

image-20230830155536067

组件

在views文件夹下编写首页Main.vue

Main.vue

<template>	
  <h1>首页</h1>
</template>
<script>
export default {
  name: "Main"
}
</script>
<style scoped>
</style>

登录页Login.vue

<template>
  <div>
    <el-form ref="loginForm" :model="form" :rules="rules" label-width="80px" class="login-box">
      <h3 class="login-title">欢迎登录</h3>
      <el-form-item label="账号" prop="username">
        <el-input type="text" placeholder="请输入账号" v-model="form.username"/>
      </el-form-item>
      <el-form-item label="密码" prop="password">
        <el-input type="password" placeholder="请输入密码" v-model="form.password"/>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" v-on:click="onSubmit('loginForm')">登录</el-button>
      </el-form-item>
    </el-form>

    <el-dialog
      title="温馨提示"
      :visible.sync="dialogVisible"
      width="30%"
      :before-close="handleClose">
      <span>请输入账号和密码</span>
      <span slot="footer" class="dialog-footer">
        <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
export default {
  name: "Login",
  data() {
    return {
      form: {
        username: '',
        password: ''
      },

      // 表单验证,需要在 el-form-item 元素中增加 prop 属性
      rules: {
        username: [
          {required: true, message: '账号不可为空', trigger: 'blur'}
        ],
        password: [
          {required: true, message: '密码不可为空', trigger: 'blur'}
        ]
      },

      // 对话框显示和隐藏
      dialogVisible: false
    }
  },
  methods: {
    onSubmit(formName) {
      // 为表单绑定验证功能
      this.$refs[formName].validate((valid) => {
        if (valid) {
          // 使用 vue-router 路由到指定页面,该方式称之为编程式导航
          this.$router.push("/main");
        } else {
          this.dialogVisible = true;
          return false;
        }
      });
    }
  }
}
</script>

<style lang="scss" scoped>
.login-box {
  border: 1px solid #DCDFE6;
  width: 350px;
  margin: 180px auto;
  padding: 35px 35px 15px 35px;
  border-radius: 5px;
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  box-shadow: 0 0 25px #909399;
}

.login-title {
  text-align: center;
  margin: 0 auto 40px auto;
  color: #303133;
}
</style>

路由

在router下

index.js

import Vue from 'vue';
import VueRouter from "vue-router";
import Main from "../views/Main";
import Login from "../views/Login";

// 显式的使用导入的组件
Vue.use(VueRouter);

export default new VueRouter({
  routes:[
    {
      path: "/login",
      name: "login",
      component: Login
    },
    {
      path: "/main",
      name: "main",
      component: Main
    }
  ]
})

main.js

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
// 导入 elementUI
import ElementUI from 'element-ui'
// 导入 elementUI 对应的 CSS
import 'element-ui/lib/theme-chalk/index.css'

Vue.use(router)
Vue.use(ElementUI)

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  render: h => h(App),
  router
})

App.vue

<template>
  <div id="app">
    <!-- 因为 main.js 中配置了,element-ui 自动渲染,所以这里只需要有一个这个标签就好了 -->
    <router-view></router-view>
  </div>
</template>

<script>

export default {
  name: 'App'
}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

测试结果:

image-20230830160118994

遇到的问题

此电脑使用的node版本时12.13.0,在依赖包下载的过程中可能就会出现依赖版本不兼容的问题。下面列举两个常见的依赖包。

1、vue-router:使用3.5.2版本

2、node-sass:4.12.0

3、sass-loader:7.3.1

路由嵌套

目录结构

image-20230831120808197

代码实现

ProFile.vue

<template>
<h1>个人信息</h1>
</template>

<script>
export default {
  name: "UserProFile"
}
</script>

<style scoped>

</style>

List.vue

<template>
<h1>用户列表</h1>
</template>

<script>
export default {
  name: "UserList"
}
</script>

<style scoped>

</style>

index.js

import Vue from 'vue';
import VueRouter from "vue-router";
import Main from "../views/Main";
import Login from "../views/Login";
import UserProFile from "../views/user/ProFile";
import UserList from "../views/user/List";

// 显式的使用导入的组件
Vue.use(VueRouter);

export default new VueRouter({
  routes:[
    {
      path: "/login",
      name: "login",
      component: Login
    },
    {
      path: "/main",
      name: "main",
      component: Main,
      children:[
        {path:"/user/profile",component:UserProFile},
        {path:"/user/list",component:UserList}
      ]
    }
  ]
})

Main.vue

<template>
  <div>
    <el-container>
      <el-aside width="200px">
        <el-menu :default-openeds="['1']">
          <el-submenu index="1">
            <template slot="title"><i class="el-icon-caret-right"></i>用户管理</template>
            <el-menu-item-group>
              <el-menu-item index="1-1">
                <!--插入的地方-->
                <router-link to="/user/profile">个人信息</router-link>
              </el-menu-item>
              <el-menu-item index="1-2">
                <!--插入的地方-->
                <router-link to="/user/list">用户列表</router-link>
              </el-menu-item>
            </el-menu-item-group>
          </el-submenu>
          <el-submenu index="2">
            <template slot="title"><i class="el-icon-caret-right"></i>内容管理</template>
            <el-menu-item-group>
              <el-menu-item index="2-1">分类管理</el-menu-item>
              <el-menu-item index="2-2">内容列表</el-menu-item>
            </el-menu-item-group>
          </el-submenu>
        </el-menu>
      </el-aside>

      <el-container>
        <el-header style="text-align: right; font-size: 12px">
          <el-dropdown>
            <i class="el-icon-setting" style="margin-right: 15px"></i>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item>个人信息</el-dropdown-item>
              <el-dropdown-item>退出登录</el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
        </el-header>
        <el-main>
          <!--在这里展示视图-->
          <router-view />
        </el-main>
      </el-container>
    </el-container>
  </div>
</template>
<script>
export default {
  name: "Main"
}
</script>
<style scoped lang="scss">
.el-header {
  background-color: #B3C0D1;
  color: #333;
  line-height: 60px;
}
.el-aside {
  color: #333;
}
</style>

测试结果:

image-20230902164119637

image-20230902164145865

image-20230902164201651

参数传递及重定向

目录结构:

image-20230902171445942

通过route传参

Main.vue

<el-menu-item index="1-1">
  <!--插入的地方-->
  <!--<router-link to="/user/profile">个人信息</router-link>-->
  <!--
    使用router传递:
      name:路由的名字
      params:需要传递的参数
      to后面的值是对象的话,使用v-bind进行绑定即可,v-bind能直接缩写为 :号
  -->
  <router-link v-bind:to="{name:'UserProFile',params:{id:1}}">个人信息</router-link>
</el-menu-item>

index.js

{
  path: "/main",
  name: "main",
  component: Main,
  children:[
    {path:"/user/profile/:id",name:"UserProFile",component:UserProFile},
    {path:"/user/list",component:UserList}
  ]
}

ProFile.vue

<template>
<!--所有的元素不能直接在根节点下-->
<div>
  <h1>个人信息</h1>
  <h1>{{$route.params.id}}</h1>
</div>
</template>

<script>
export default {
  name: "UserProFile"
}
</script>

<style scoped>

</style>

测试:

参数id传递成功

image-20230902171847649

通过 props 解耦

index.js

{
  path: "/main",
  name: "main",
  component: Main,
  children:[
    // props:true 通过props方式进行传递
    {path:"/user/profile/:id",name:"UserProFile",component:UserProFile,props:true},
    {path:"/user/list",component:UserList}
  ]
}

ProFile.vue

<template>
<!--所有的元素不能直接在根节点下-->
<div>
  <h1>个人信息</h1>
  <!--<h1>{{$route.params.id}}</h1>-->
  <!--直接获取props中的参数值-->  
  <h1>{{id}}</h1>
</div>
</template>

<script>
export default {
  props:['id'],
  name: "UserProFile"
}
</script>

<style scoped>

</style>

Main.vue

<el-menu-item index="1-1">
  <!--插入的地方-->
  <!--<router-link to="/user/profile">个人信息</router-link>-->
  <!--
    使用router传递:
      name:路由的名字
      params:需要传递的参数
      to后面的值是对象的话,使用v-bind进行绑定即可,v-bind能直接缩写为 :号
  -->
  <router-link v-bind:to="{name:'UserProFile',params:{id:1}}">个人信息</router-link>
</el-menu-item>	

重定向

Main.vue

<el-menu-item index="1-3">
  <!--重定向到main页面-->
  <router-link to="/gohome">回到首页</router-link>
</el-menu-item>

index.js

{
  path:"/gohome",
  // 重定向到main页面
  redirect:"/main"
}

测试

image-20230902173329090

image-20230902173346310

已经重定向到了首页

取消路径的#号

路径中带着#号

image-20230902183440262

index.js

export default new VueRouter({
  // 使用 mode:"history" ,路径中不用带#号
  mode:"history",
  routes:[
    {
      path: "/login",
      name: "login",
      component: Login
    },

image-20230902183700231

404 和 路由钩子

404

目录结构

image-20230902175538188

新建视图组件 :404.vue

<template>
  <div>
    <h1>404,页面走丢了!</h1>
  </div>
</template>
<script>
export default {
  name: "NotFind"
}
</script>
<style scoped>
</style>

把 404 组件配置到路由信息中 :index.js

{
  path:"/*",
  component:NotFind
}

启动页面,随便访问一个不存在的路径

image-20230902175712065

路由钩子

基本使用

beforeRouteEnter :在进入路由之前执行的钩子

beforeRouteLeave :在离开路由之前执行的钩子

ProFile.vue

<template>
<!--所有的元素不能直接在根节点下-->
<div>
  <h1>个人信息</h1>
  <!--<h1>{{$route.params.id}}</h1>-->
  <h1>{{id}}</h1>
</div>
</template>

<script>
export default {
  props:['id'],
  name: "UserProFile",
  beforeRouteEnter:(to,from,next)=>{
    alert("进入路由之前");
    next();
  },
  beforeRouteLeave:(to,from,next)=>{
    alert("路由离开之前");
    next();
  }
}
</script>

<style scoped>

</style>

参数说明

  • to:路由将要跳转的路径信息
  • from:路径跳转前的路径信息
  • next:路由的控制参数
    • next() 跳入下一个页面
    • next(’/path’) 改变路由的跳转方向,使其跳到另一个路由
    • next(false) 返回原来的页面
    • next((vm)=>{}) 仅在 beforeRouteEnter 中可用,vm 是组件实例

页面效果

image-20230902184446759

image-20230902184500900

image-20230902184601056

image-20230902184619695

在钩子函数中使用异步请求

目录结构

image-20230902191023482

安装 Axios

axios版本0.19.0,

版本:

vue:2.9.6

axios:0.19.0

image-20230902185109792

vue-axios

image-20230902185713187

引用 Axios

main.js引用 Axios

import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(axios,VueAxios)

data.json

{
  "name": "呵呵",
  "url": "https://blog.csdn.net/weixin_44449838",
  "page": 123,
  "isNonProfit": true,
  "address": {
    "street": "塔克拉玛干沙漠",
    "city": "新疆",
    "country": "中国"
  },
  "links": [
    {
      "name": "Google",
      "url": "http://www.google.com"
    },
    {
      "name": "Baidu",
      "url": "http://www.baidu.com"
    }
  ]
}

ProFile.vue

<template>
<!--所有的元素不能直接在根节点下-->
<div>
  <h1>个人信息</h1>
  <!--<h1>{{$route.params.id}}</h1>-->
  <h1>{{id}}</h1>
</div>
</template>

<script>
export default {
  props:['id'],
  name: "UserProFile",
  beforeRouteEnter:(to,from,next)=>{
    console.log("进入路由之前");

    // vm 代表当前的这个vue组件对象
    next(vm => {
      //进入路由之前执行getData方法
      vm.getData();
    });

  },
  beforeRouteLeave:(to,from,next)=>{
    alert("路由离开之前");
    next();
  },

  //axios
  methods: {

    getData: function () {
      this.axios({
        method: 'get',
        url: 'http://localhost:8080/static/mock/data.json'
      }).then(function (response) {
        console.log(response)
      })
    }

  }

}
</script>

<style scoped>

</style>