1. 概述

1.1. Vue概述

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

1.2. 前端知识体系

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

1.3. 前端三要素

  • HTML (结构) :超文本标记语言(Hyper Text Markup Language) ,决定网页的结构和内容
  • CSS (表现) :层叠样式表(Cascading Style sheets) ,设定网页的表现样式
  • JavaScript (行为) :是一种弱类型脚本语言,其源代码不需经过编译,而是由浏览器解释运行,用于控制网页的行为

1.4. 表现层(CSS)

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

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

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

1.5. CSS预处理器

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

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

1.6. 行为层(JavaScript)

JavaScript一门弱类型脚本语言,其源代码在发往客户端运行之前不需经过编译,而是将文本格式的字符代码发送给浏览器由浏览器解释运行。
Native原生JS开发
原生JS开发,也就是让我们按照[ECMAScript] 标准的开发方式,简称是ES,特点是所有浏览器都支持。截止到当前博客发布时间,ES 标准已发布如下版本:

  • ES3
  • ES4 (内部,未征式发布)
  • ES5 (全浏览器支持)
  • ES6 (常用,当前主流版本: webpack打包成为ES5支持! )
  • ES7
  • ES8
  • ES9 (草案阶段)

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

1.7. TypeScript

TypeScript是一种由微软开发的自由和开源的编程语言。它是JavaScript的一个超集,而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程。由安德斯海尔斯伯格(C#、Delphi、TypeScript 之父; .NET 创立者)主导。
该语言的特点就是除了具备ES的特性之外还纳入了许多不在标准范围内的新特性,所以会导致很多浏览器不能直接支持TypeScript语法,需要编译后(编译成JS)才能被浏览器正确执行。

1.8. 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.9. UI框架

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

JavaScript 构建工具

  • Babel: JS编译工具,主要用于浏览器不支持的ES新特性,比如用于编译TypeScript
  • WebPack: 模块打包器,主要作用是打包、压缩、合并及按序加载
    注:以上知识点将WebApp开发所需技能全部梳理完毕

1.10. 三端合一

混合开发(Hybid App)
主要目的是实现一套代码三端统一(PC、Android:.apk、iOS:.ipa )并能备够调用到底层件(如:传感器、GPS、 摄像头等),打包方式主要有以下两种:

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

1.11. 后端技术

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

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

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

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

2. MVVM

2.1. 什么是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.png

2.2. 为什么要使用MVVM

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

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

2.3. Vue 是 MVVM 模式的实现者

image.png

  • Model : 模型层,在这里表示JavaScript对象
  • View : 视图层,在这里表示DOM (HTML操作的元素)
  • ViewModel : 连接视图和数据的中间件,Vue.js就是MVVM中的ViewModel层的实现者在MVVM架构中,是不允许数据和视图直接通信的,只能通过ViewModel来通信,而ViewModel就是定义了一个Observer观察者

ViewModel 能够观察到数据的变化,并对视图对应的内容进行更新
ViewModel 能够监听到视图的变化,并能够通知数据发生改变
Vue.js 就是一个MVVM的实现者,他的核心就是实现了DOM监听数据绑定

3. 第一个 Vue 程序

  1. 新建一个空项目,新建一个包 :chapter01

image.png

  1. 新建一个 HTML5 项目,并编写
  2. 打开页面
<!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.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
    <script>
      var vm = new Vue({
        // 2、绑定 app 元素
        el: "#app",
        // Model 层
        // 3、插入数据,键值对
        data: {
          message: "hello,vue"
        }
      });
    </script>
  </body>
</html>

image.png

  1. 打开开发者工具,选择 Console输入 ,并回车
vm.message="hehe"

发现页面的数据也变了
这就是 ViewModel 双向绑定
view层的数据 和 message 这个变量绑定,message 改变页面上的数据也改变了

4. 指令

4.1. 示例

编写 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.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
    <script>
      var vm = new Vue({
        // 2、绑定 app 元素
        el: "#app",
        // Model 层
        // 3、插入数据,键值对
        data: {
          message: "hello,vue"
        }
      });
    </script>
  </body>
</html>

打开页面查看
image.png
发现 使用 v-bind: 也可以把变量绑定到元素上

4.2. 概述

指令 (Directives) 是带有 v- 前缀的特殊 attribute。指令 attribute 的值预期是单个 JavaScript 表达式 (v-for 是例外情况,稍后我们再讨论)。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。

4.3. v-if

编写 HTML

<div id="app">
  <span v-if="ok===true">YES</span>
  <span v-else>No</span>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
  var vm = new Vue({
    el: "#app",
    data: {
      ok: true
    }
  });
</script>

打开页面
image.png
修改 ok 的值
image.png

4.4. v-else-if

<div id="app">
  <span v-if="str==='A'">AAA</span>
  <span v-else-if="str==='B'">BBB</span>
  <span v-else>Other</span>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
  var vm = new Vue({
    el: "#app",
    data: {
      str: 'A'
    }
  });
</script>

打开页面
image.png
修改 str 的值
image.png
image.png

4.5. for

<div id="app">
  <ul>
    <!--类似于java 的 foreach ,
    从 items 中遍历出的每一项命名为 item-->
    <li v-for="item in items">{{item.message}}</li>
  </ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
  var vm = new Vue({
    el: "#app",
    data: {
      items: [
        {message: "test-1"},
        {message: "test-2"},
        {message: "test-3"}
      ]
    }
  });
</script>

打开页面
image.png

5. 监听事件

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

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

打开页面
image.png

6. 双向绑定

6.1 什么是数据双向绑定?

vue是一个mvvm框架,即数据双向绑定,即当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化。这也算是vue的精髓之处了。
值得注意的是,我们所说的数据双向绑定,一定是对于UI控件来说的,非UI控件不会涉及到数据双向绑定。 单向数据绑定是使用状态管理工具(如redux)的前提。如果我们使用vuex,那么数据流也是单项的,这时就会和双向数据绑定有冲突,我们可以这么解决

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

在vue中,如果使用vuex,实际上数据还是单向的,之所以说是数据双向绑定,这是用的UI控件来说,对于我们处理表单,vue的双向数据绑定用起来就特别舒服了。
即两者并不互斥, 在全局性数据流使用单项,方便跟踪; 局部性数据流使用双向,简单易操作。

6.3 表单中使用双向数据绑定

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

6.4 使用

1. 输入框

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

在页面中修改 message 的值
image.png
直接在输入框中输入
image.png

2. 单选框

<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.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
  var vm = new Vue({
    el: "#app",
    data: {
      sex: ""
    }
  });
</script>

打开页面
image.png
可以发现,这里绑定的是单选框的 Value

3. 多选框

<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.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
  var vm = new Vue({
    el: "#app",
    data: {
      checkedNames: []
    }
  });
</script>

image.png

4. 下拉框

<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.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
  var vm = new Vue({
    el: "#app",
    data: {
      selected : ""
    }
  });
</script>

image.png

7. 组件

7.1. 概述

  • 组件是可复用的 Vue 实例,也就是在开发过程中可以把重复的部分封装为组件
  • 组件的组织
    image.png例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。

7.2. 第一个组件的 Demo

<div id="app">
  <my-component></my-component>
  <my-component></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
  // 定义组件
  Vue.component("my-component",{
    template: '<li>AA</li>'
  });

  var vm = new Vue({
    el: "#app"
  });
</script>

image.png

7.3. 通过Data传递数据

<div id="app">
  <!--  利用 v-for 把 items 的元素取出,
  再通过 v-bind 绑定数据: 把 item1 绑定在了 item2 上-->
  <my-component v-for="item1 in items" v-bind:item2="item1"></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
  // 定义组件
  Vue.component("my-component",{
    // 通过 item2 接收 item1 数据
    props: ['item2'],
    template: '<li>{{item2}}</li>'
  });

  var vm = new Vue({
    el: "#app",
    data: {
      items: ["AAA","BBB","CCC"]
    }
  });
</script>

image.png

8. Axios 异步通信

8.1. 概述

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

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

8.2. 为什么要使用 Axios

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

8.3. 前提

确认 IDEA 的 JavaScript 支持 ES6
image.png

8.4 第一个 Axios 应用程序

  1. 因为在实际开发中,大多使用的是 JSON 格式数据,所以这里新建一个 JSON 格式的文件
  2. 编写 HTML - 获取 本地的 Json 数据
  3. 打开页面,打开开发者工具可以发现 Axios 和 AJax 一样是异步的通信
    image.png
    也可以看到已经获取到了数据
    image.png
  4. 编写 HTML - 把获得的 Json 渲染到页面
  5. 页面
    image.png
{
  "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"
    }
  ]
}
<div id="vue">

</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<!-- axios 的包-->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
  var vm = new Vue({
    el: "#vue",
    data: {},
    // 钩子函数,在主流程执行过程中间执行的方法
    mounted(){
      axios.get('../data.json').then(response=>(console.log(response.data)));
    }
  });
</script>
<div id="vue">
  <!--    需要渲染的字段名 -->
  <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.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<!-- axios 的包-->
<script src="https://unpkg.com/axios/dist/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>

8.5 解决闪烁问题

上面那个 Demo 写好,在刷新页面的时候会发现,最开始出现的是模板,过一会儿后数据才出来
image.png
这样对用户不太友好,对数据也不安全,所以用如下方法解决
在 HTML 上方写一个 < style >< /style >

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

<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>

这样虽然数据还是会过一会儿才出来,但是已经看不到模板了。

9. Vue 的生命周期

Vue 实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载 DOM、渲染 ->更新 ->渲染、卸载等一系列过程,这称为 Vue 的生命周期。
在 Vue 的整个生命周期中,它提供了一系列的事件,可以让我们在事件触发时注册 JS 方法,可以放我们自己用自己注册的 JS 方法控制整个大局,在这些事件响应方法中的 this 直接指向的是 Vue 的实例。
image.png

10. 计算属性

  • 计算属性 : 把计算出来的结果,保存在属性中。
  • 好处 :在内存中运行,虚拟 DOM
  • 编写代码
  • 体验区别打开页面、打开开发者模式、使用控制台
<div id="vue">
  <!-- 调用方法 -->
  <p>currentTime1 : {{currentTime1()}}</p>
  <!-- 调用属性 -->
  <p>currentTime2 : {{currentTime2}}</p>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
  var vm = new Vue({
    el: "#vue",
    data: {
      message: "hello."
    },
    methods: {
      currentTime1: function (){
        // 返回当前时间戳
        return Date.now();
      }
    },
    // 计算属性
    computed: {
      // 方法名不能一样
      currentTime2: function (){
        // 返回当前时间戳
        return Date.now();
      }
    }
  });
</script>
  1. 调用的时候普通方法是调用方法名 ; 计算属性调用时是属性名
    image.png
  2. 普通函数调用一次执行一次 ; 计算属性把计算完的结果,当成属性,存在内存中
    image.png
  • 什么时候计算属性会改变修改计算属性中的方法
// 计算属性
computed: {
  // 方法名不能一样
  currentTime2: function (){
    // 返回当前时间戳
    return Date.now() +"  | "+this.message;
  }
}

打开页面、打开开发者模式、使用控制台
image.png
所以只要计算属性方法体中有数据发生改变,计算属性就会改变。

11. 内容分发— slot

  • 插槽(slot) :动态可插拔的组件
  • 简单案例
<div>
  <p>数据列表(原本的)</p>
  <ul>
    <li>AAA</li>
    <li>BBB</li>
    <li>CCC</li>
  </ul>
</div>
————————————————————————————————
<div id="vue">
  <list>
    <!--绑定插槽 : 使用 slot 属性绑定,引号里的值,必须和下面的 name 属性一样-->
    <!--绑定数据 : 冒号后面是组件中定义的值
    引号里面是 data 数据的字段值
    不能混淆-->
    <list-title slot="list-title" :title="l_title"></list-title>
    <list-items slot="list-items" v-for="item in l_items" :item="item"></list-items>
  </list>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/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: "#vue",
    data: {
      l_title: "标题————",
      l_items:["AA","BBB","CCCC"]
    }
  });
</script>

页面效果
image.png

12. 自定义事件内容分发

  • 在上述案例的基础上,希望在每一行后面加一个删除按钮,且点击删除后删除改行
  1. 先稍作修改,添加删除按钮,绑定点击事件,点击后打印下标
  2. 在 vue 对象中添加删除方法
  3. 测试上面写的两个方法点击删除按钮image.png在控制台调用 removeItem 方法image.png
    这两个方法分别成功,下面该如何让这两个方法产生联系
  4. 通过 this.$emit(“自定义事件名”,参数) 让组件调用事件
  5. 测试
    image.png
  6. 流程简单图解
    image.png
<list-items slot="list-items" v-for="(item,index) in l_items" :item="item" :index="index"></list-items>
 
var vm = new Vue({
  el: "#vue",
  data: {
  l_title: "标题————",
  l_items:["AA","BBB","CCCC"]
  },
  methods: {
  removeItem: function (index){
  // 打印信息
  console.log("删除了"+this.l_items[index]);
  // 表示从 index 开始,删除 n 个元素
  this.l_items.splice(index,1);
  }
  }
  });
<!--数据绑定 :把 items 中的每一项元素遍历出来命名为 item 再和下面的 item 绑定-->
<!--事件绑定 :自定义一个名为 diyremove 的事件,先和vue对象中的 removeItem 方法绑定
再去到组件中的 remove 和 diyremove 事件绑定-->
<!--注意 : 属性值都要小写,大写不生效,也不会报错 ; 在自定义事件绑定方法的时候 v-on 不能缩写-->
<list-items slot="list-items" v-for="(item,index) in l_items" :item="item" :index="index" v-on:diyremove="removeItem(index)"></list-items>

13. Vue-cli

13.1 什么是vue-cli

vue-cli 官方提供的一个脚手架,用于快速生成一个 vue 的项目模板;
预先定义好的目录结构及基础代码,就好比咱们在创建 Maven 项目时可以选择创建一个骨架项目,这个骨架项目就是脚手架,我们的开发更加的快速;
主要功能:

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

13.2 需要的环境

  1. 下载 Node.js ,选择 windows 64位
  2. 安装 NodeJs ,一直下一步即可
  3. 查看是否安装成功cmd 下输入 node -v,查看是否能够正确打印出版本号即可!
  • 安装 Node.js 淘宝镜像加速器(cnpm)
  • 安装vue-cli
CMD 命令)
-g 就是全局安装
npm install cnpm -g --registry=https://registry.npm.taobao.org

# 或使用如下语句解决 npm 速度慢的问题
npm install --registry=https://registry.npm.taobao.org

安装过程有点慢
安装位置为 :C:\Users\Administered\AppData\Roaming\npm

(CMD 命令)
 cnpm install vue-cli -g	

vue list

image.png

13.3 Vue-cli 程序

  1. 在文件夹中使用cmd创建一个名为 myvue 的vue项目并用webpack打包工具打包
  2. 初始化并运行myvue项目
(CMD 命令)
 # 先找到要创建该文件的目录
 # 这里的 myvue 是项目名称,可以根据自己的需求起名
 vue init webpack myvue

image.png
说明:
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,我们手动执行;运行结果!
生成的文件
image.png

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

运行成功后
image.png

14. Webpack

14.1 什么是webpack

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

14.2 为什么要使用webpack

如今的很多网页其实可以看做是功能丰富的应用,它们拥有着复杂的JavaScript代码和一大堆依赖包。为了简化开发的复杂度,前端社区涌现出了很多好的实践方法

  1. 模块化,让我们可以把复杂的程序细化为小的文件;
  2. 类似于TypeScript这种在JavaScript基础上拓展的开发语言:使我们能够实现目前版本的JavaScript不能直接使用的特性,并且之后还能能装换为JavaScript文件使浏览器可以识别;
  3. scss,less等CSS预处理器……
    这些改进确实大大的提高了我们的开发效率,但是利用它们开发的文件往往需要进行额外的处理才能让浏览器识别,而手动处理又是非常繁琐的,这就为WebPack类的工具的出现提供了需求。

14.3 安装 Webpack

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

(CMD 命令)
 npm install webpack -g --registry=https://registry.npm.taobao.org
 npm install webpack-cli -g --registry=https://registry.npm.taobao.org

测试是否安装成功

webpack -v
webpack-cli -v

14.4 配置

创建 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 命令打包

14.5 使用webpack

  1. 创建项目 : webpack-study
  2. 创建一个名为modules的目录,用于放置JS模块等资源文件
  3. 在modules下创建模块文件 :hello.js用于编写JS模块相关代码
// 暴露一个方法
exports.sayHi = function(){
  document.write("<h1>Hello World</h1>");
}
  1. 在 modules 下创建一个名为 main.js 的入口文件,用于打包时设置entry属性
// 引入 hello.js,相当于java的对象 
var hello = require("./hello");
// 调用 hello.js 中的方法
hello.sayHi();
  1. 在 webpack-study 目录下创建 webpack.config.js (注意是:点)配置文件,使用webpack命令打包
// 把 module 导出
module.exports = {
  // 目标文件
  entry: './modules/main.js',
  // 输出地址
  output: {
    filename: "./js/bundle.js"
  }
}
  1. 把刚刚编写的文件打包进入 webpack-study 目录

image.png

  1. 在 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>
  1. 打开页面
    image.png

15. vue-router

15.1 说明

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

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

15.2 安装

基于第一个vue-cli进行测试学习
cmd 进入 myvue 目录,并执行

可以用
cnpm install vue-router --save-dev
没成功
npm install vue-router --save-dev --registry=https://registry.npm.taobao.org

15.3 使用

  1. 清理代码删除 src 目录下的图片、components 目录下的组件修改 App.vue
  2. 启动项目
  3. 修改 App.vue
  4. 在 components 中新建一个 Vue 组件 :Content.vue
  5. 在 components 中新建一个 Vue 组件 :Main.vue
  6. 在 src 下新建一个包(router),在该包中新建一个文件:index.js
  7. 修改 main.js
  8. 修改 App.vue 中的 template 部分
  9. 打开页面
    image.png
    image.png
    image.png
<template>
  <div id="app">
  </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>
<template>
  <div id="app">
    <h1>呵呵</h1>
  </div>
</template>

发现项目自动 Bulid ,页面自动刷新
这就是 Vue 的热部署

<template>
  <h1>Content</h1>
</template>
<script>
  export default {
    name: "Content"
  }
</script>
<!-- 加上 scoped 表示只会在当前组件生效 -->
<style scoped>
</style>
<template>
  <h1>首页</h1>
</template>
<script>
  export default {
    name: "main"
  }
</script>
<style scoped>
</style>
// 导入文件
import Vue from "vue";
import VueRouter from "vue-router";
// 导入组件
import Content from "../components/Content";
import Main from "../components/Main";

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

// 配置导出路由
export default new VueRouter({
  routes: [
    {
      // 类似于 @RequestMapping 接收一个请求,返回一个页面
      // 路由的路径
      path: '/content',
      // 配置名称
      name: 'content',
      // 跳转的组件
      component: Content
    },
    {
      // 路由的路径
      path: '/main',
      // 配置名称
      name: 'Main',
      // 跳转的组件
      component: Main
    }
  ]
});
import Vue from 'vue'
import App from './App'
// 导入 vue-router 的路由配置
// 这里是写在 index.js 文件中的所以导入该文件
// 因为文件名是 index 会自动扫描该文件,所以index可省
// 注意!! 这里必须写 router ,写错前端页面就报错
import router from "./router/index";

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  // 配置路由,上面的组件名
  router,
  components: { App },
  template: '<App/>'
})
<template>
  <div id="app">
    <h1>呵呵</h1>
    <!--跳转链接,点击链接显示对应内容-->
    <!--类似于原来的 <a></a> ;
    to 类似于原来的 href,后面的值就是配置的路由-->
    <router-link to="/main">首页</router-link>
    <router-link to="/content">内容页</router-link>
    <!--展示视图,理解为用于展示上面两个链接对应内容的区域-->
    <router-view></router-view>
  </div>
</template>

16. Vue+ElementUI

  1. 创建一个名为 vue-elementui 的项目vue init webpack vue-elementui
  2. 安装 vue-router、element-ui、sass-loader、node-sass 四个插件
# 进入工程
cd vue-elementui
# 安装 vue-router
cnpm install vue-router --save-dev 
# 安装 element-ui
cnpm i element-ui -S 
# 安装依赖
cnpm install 
# 安装 SASS 加载器
cnpm install sass-loader node-sass --save-dev
# 启动测试
npm run dev


测试报错:
cnpm install --save vue-hot-reload-api
  1. 把项目恢复为一个空项目删除 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>
  1. 新建文件夹router :存放路由信息
    views :存放 视图组件
    components :存放功能性的组件
    image.png
  2. 在 views 包下新建一个视图组件:Main.vue
<template>
  <h1>首页</h1>
</template>
<script>
  export default {
    name: "Main"
  }
</script>
<style scoped>
</style>
  1. 在 views 包下新建一个视图组件: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>
  1. 在 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
    }
  ]
});
  1. 修改 main.js
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)

new Vue({
  el: '#app',
  // 配置 elementUI
  render: h => h(App),
  router
})
  1. 修改 App.vue
<template>
  <div id="app">
    <!-- 因为 main.js 中配置了,element-ui 自动渲染,所以这里只需要有一个这个标签就好了 -->
    <router-view></router-view>
  </div>
</template>x
  1. 启动项目如果报错,尝试降 sass-loader 的版本找到 package.json 文件
    image.png
    找到 sass-loader 属性
    image.png
    把后面的版本号 改为 ^7.3.1
    重新安装环境依赖npm install
  2. 随便输入用户名、密码,登录发现进入首页查看 Login.vue 代码, 在 < script>< /script>中
    image.png

安装步骤与前文一样

重启项目,访问 http://localhost:8080/#/login
image.png

17. 路由嵌套

  • 嵌套路由又称子路由,在实际应用中,通常由多层嵌套的组件组合而成,例如:
    image.png
  1. 在 views 中新建一个 user包
  2. 在 user 包下,新建 List.vue
<template>
  <h1>用户列表</h1>
</template>
<script>
  export default {
    name: "List"
  }
</script>
<style scoped>
</style>
  1. 在 user 包下,新建 Profile.vue
<template>
  <h1>个人信息</h1>
</template>
<script>
  export default {
    name: "Profile"
  }
</script>
<style scoped>
</style>
  1. 修改 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>
  1. 修改 index.js ,路由信息
import Vue from 'vue';
import VueRouter from "vue-router";

import Main from "../views/Main";
import Login from "../views/Login";

import List from "../views/user/List";
import Profile from "../views/user/Profile";

// 显式的使用导入的组件
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: Profile
        },{
          path: "/user/list",
          component: List
        }
      ]
    }
  ]
});
  1. 在 Main.vue 中插入路由链接,展示视图
    image.png
    image.png
  • 修改路由的模式有两种模式 :1、hash :路径中有 # ; 2、history :路径中不带 #修改文件 index.js
    image.png
  1. 打开页面
    image.png

18. 参数传递及重定向

18.1 通过route传参

  1. 修改前端 < router-link> 标签
    image.png
  2. 修改 index.js 中的路由信息
    image.png
  3. 把参数在前端页面取出,修改 :Profile.vue注意是 route 不是 router
    image.png
  4. 打开页面
    image.png

18.2 通过 props 传参

  • 在登录完成后显示用户名
  1. 修改 Login.vueimage.png
  2. 修改 index.js
    image.png
  3. 首页获取 :Main.vue
    image.png

18.3 重定向

  1. 修改 index.js ,添加重定向信息
    image.png
  2. 修改 Main.vue
    image.png
  3. 打开页面

image.png

19. 404 和 路由钩子

19.1 404

  1. 新建视图组件 :404.vue
  2. 把 404 组件配置到路由信息中 :index.js
    image.png
  3. 启动页面,随便访问一个不存在的路径
<template>
  <div>
    <h1>404,页面走丢了!</h1>
  </div>
</template>
<script>
  export default {
    name: "404"
  }
</script>
<style scoped>
</style>

image.png

19.2 路由钩子

1. 基本使用

  • beforeRouteEnter :在进入路由执行的钩子
  • beforeRouteLeave :在离开路由执行的钩子
  1. 修改 Profile.vue
    image.png
  2. 打开页面
  • 参数说明:
    • to:路由将要跳转的路径信息
    • from:路径跳转前的路径信息
    • next:路由的控制参数
      • next() 跳入下一个页面
      • next(’/path’) 改变路由的跳转方向,使其跳到另一个路由
      • next(false) 返回原来的页面
      • next((vm)=>{}) 仅在 beforeRouteEnter 中可用,vm 是组件实例

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

  1. 安装 Axios
  2. main.js引用 Axios
  3. 准备数据只有我们的 static 目录下的文件是可以被访问到的,所以我们就把静态文件放入该目录下。在 static 下新建文件夹 mock (测试数据),新建一个 data.json
  4. 在 beforeRouteEnter 中进行异步请求 ,修改 Profile.vue
  5. 访问 /user/profile 页面控制台输出了获取到的数据
cnpm install --save vue-axios
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
{
  "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"
    }
  ]
}
export default {
  //第二种取值方式
  // props:['id'],
  name: "UserProfile",
  //钩子函数 过滤器
  beforeRouteEnter: (to, from, next) => {
    //加载数据
    console.log("进入路由之前")
    next(vm => {
      //进入路由之前执行getData方法
      vm.getData()
    });
  },
  beforeRouteLeave: (to, from, next) => {
    console.log("离开路由之前")
    next();
  },
  //axios
  methods: {
    getData: function () {
      this.axios({
        method: 'get',
        url: 'http://localhost:8080/static/mock/data.json'
      }).then(function (response) {
        console.log(response)
      })
    }
  }
}
Logo

前往低代码交流专区

更多推荐