前端之路(Vue框架篇)

Vue 介绍

  1. vue 中文网

  2. github 下载地址

  3. Vue.js (读音 /vju:/ view)

  4. 渐进式 JavaScript 框架3.1 渐进式 :

    小型项目 就可以使用 vue 就高度了随着页面的复杂程序提高,就要学习 vue-rouer 来管理更多的页面再随着项目的数据越来越多,管理数据也变得麻烦起来了,就开始使用 vuex 来管理数据

框架和库的区别 

1. 库(Library) , 代表 : jquery

  • 库就是一系列函数的集合, 我们开发人员在使用库的时候,想要完成什么样的功能,就调用库中提供的某个方法

比如 : 想要添加样式, 就调用 jquery 中的 .css() / .addClass()

  • 库起到了一个辅助的作用, 在使用库的是时候,是由开发人员说了算, 也是由开发人员起主导作用.

比如 : 想给 A:设置样式 A.css(), B:addClass() C:style.background='red'

2. 框架 (Framework), 代表:vue

  • 在使用框架的时候,是由框架说了算,由框架起到了主导作用,

  • 框架是一套完整的解决方案,框架中制定了一套规则,使用框架的时候,只需要按照规则,把代码放到合适的地方,然后框架会在合适的时机,主动调用开发人员的代码

比如 : 想用vue,组件里遍历就得使用 v-for, 下次不用 v-for 了,使用 for 不行 v-for='item in list'

3. 主要区别 : 控制反转

也就是 : 谁起到了主导作用

  • 使用库的时候 : 开发人员起主导作用

  • 使用框架的时候:框架起到了主导作用

  • 从体量上看,框架一般比库大

  • 会发现使用框架的时候,会受到很多限制

MVC + MVVM 

MVC

  1. MVC 是一种软件架构模式,也有人叫做设计模式

  2. M : Model 数据模型 (专门用来操作数据,数据的 CRUD)

  3. V : View 视图 (对于前端来说,就是页面)

  4. C : Controller 控制器 (是视图和数据模型沟通的桥梁,用于处理业务逻辑)

  5. 看图

MVVM

Vue 使用的是 MVVM 模式为什么要学习 MVVM ?

  • MVVM ===> M / V / VM

  • M : model 数据层

  • V : view 视图层

  • VM : ViewModel 视图模型

  • 核心 : M <===> VM <===> V

MVVM 优势

  • MVC 模式 将应用程序划为三个部分,实现职责分离

    • 但是,在前端中,经常要通过 js 代码来进行一些逻辑操作,最终还要把这些逻辑操作展示页面中, 也需要频繁的操作DOM

    • 比如 : ajax 请求、添加、修改、设置样式、动画

  • MVVM 提出来的思想 通过 数据双向绑定 让数据自动的双向同步

    • V (修改视图) --> M

    • M (修改数据) --> V

  • 采用的是 : 数据驱动视图的思想, 数据是核心

  • 以后如果想要操作 DOM, 立马想到的不是应该是拿到元素设置,而是数据

Vue 中的 MVVM

  • 注意 : 不推荐直接手动操作 DOM

    每个人操作 DOM 的方法不一样,会造成性能不一样官网 : 虽然没有完全遵循 MVVM 模型,但是 Vue 的设计也受到了它的启发。因此在文档中经常会使用 vm (ViewModel 的缩写) 这个变量名表示 Vue 实例。

学习 Vue 要转化思想

  • 数据驱动视图 : 不要再想着怎么操作 DOM, 而是想着如何操作数据

起步 - Hello Vue

基本使用

  1. 安装 : npm i vue (小写)

  2. 导入 : <script src='./vue.js'></script>

  3. 实例 vue

const vm = new Vue({
  // 指定 vue 管理的边界
  el: '#app',
  // 提供视图中 需要的数据
  // 视图可以直接使用data中的数据
  data: {
    msg: 'xxx'
  }
})

使用注意点

  1. vm 官网建议

  2. Vue 构造函数首字母大写

  3. 参数是一个对象

  4. id='#app', 其他也可以

  5. 边界外的无法使用 msg

{{}} 插值表达式

  1. {{}} Mustache 小胡子语法, 插值表达式

  2. 作用 : 使用{{}}data中获取数据,并展示在模板中

  3. 说明 : {{}} 中只能出现 js 表达式

  • 表达式 (有返回值的)

    • 常见的数据类型 1 'abc' false [] {}

    • 数据类型 和 运算符结合在一起1+2 arr.join('-') true ? 123 : 321

  • 语句 if语句 for语句

  1. {{}} 语法 不能作用在 HTML 元素的属性上

数据双向绑定

一个 input + v-model

 v-model 指令 : 数据双向绑定的指令
 作用 : 把data中的msg值 和  input上的值 绑定到一起
 注意 : v-model只能用在 表单控件上 (input checkbox 等)
 > 可以在浏览器分别演示 V => M  和 M =>V

Object.defineProperty

let obj = {}
let temp
​
obj.name = 'zhanhgsan'
​
// 参数1 : 要给哪个对象设置属性
// 参数2 : 给对象设置什么属性
// 参数3 : 属性的修饰符
Object.defineProperty(obj, 'name', {
  set: function(newVal) {
    console.log('赋值了', newVal)
  },
  get: function() {
    console.log('取值了')
    return temp
  }
})

数据双向绑定的原理

  1. <input type="text" id="txt" />

  2. 演示 : V ==> M

//1. 拿到文本框
const txt = document.getElementById('txt')
//2. 时刻监听txt ,拿到最新的值
txt.oninput = function() {
  console.log(this.value)
  obj.name = this.value
}
​
//3. 数据模型
var obj = {}
let temp
​
Object.defineProperty(obj, 'name', {
  // 给属性赋值的时候会掉
  set: function(newVal) {
    console.log('调用了set', newVal)
    temp = newVal
​
    txt.value = newVal
  },
  get: function() {
    console.log('调用了get')
    return temp
  }
})
  1. V => M

//1. 获取 input的值,最新值
//2. 通过监听oninput 拿到最新值
//3. 把最新值赋值给 obj.name
//4. 就会掉了set方法,就会修改了数据
  1. M => V

//1. obj.name = 'xxx'
//2. 调用 set方法
//3. 把值赋值给input元素

指令学习

指令

  • 指令 : 就是一个特殊的标记, 起一个辅助作用, 使 html 具备原来没有的功能

  • vue 中 所有的指令, 都是以 v-开头的

  • 比如 : v-model v-bind v-if v-for 等等

v-model (常用)

说明 : 用在表单元素中, 用来实现数据双向绑定 (input checkbox 等等)作用 : 将 数据txt文本框的值 绑定到一起, 任何一方发生改变,都会引起对方的改变注意 : v-model 在不同类型的表单元素中,该指令的作用不同

<!-- 文本输入框 绑定的是值 -->
<input type="text" v-model="txt" />
<!-- 多选框  绑定的选中状态 -->
<input type="checkbox" v-model="isChecked" />

v-text 和 v-html

说明 : 设置文本内容

  1. v-text : 相当于之前的 innerText , 设置文本内容(不识别 html 标签) == 标签内部{{}}

  2. v-html : 相当于之前的 innerHTML , 设置文本内容(是被 html 标签)

  3. 数据

   msg1: '<a>这是一条信息</a>',
   msg2: '<a href="#">我也是一条信息</a>'

v-bind (常用)

说明 : 动态绑定数据 (单向)出现原因 : 在 HTML 属性中, 无法使用插值表达式步骤:

// 加载静态数据
 <a href="https://wbaidu.com">aaa</a>
// 想加载动态数据  {{ }}可以获取data中的数据
// 但是 {{}} 不能使用在属性中
<a href="{{ src }}">aaa</a>
// 所以使用v-bind
<a v-bind:href="{{ src }}">aaa</a>   ok
 <img v-bind:src="src">   ok

缩略 : v-bind 全部省略 只留下一个:改为 :

<a :href="src">aaa</a> ok
<img :src="src" /> ok

以后 使用静态加载数据 : <a href="https://wbaidu.com">aaa</a>动态加载数据 : <a :href="href">aaa</a>

v-bind 和 v-model 的区别

//  v-model :  数据双向绑定         表单元素上
//   :      :  动态绑定数据(单向)    任意元素动态读取属性
​
容易出错点 : 
<!-- v-model 数据双向绑定 -->
<!--场景 :  表单元素中 -->
<input type="checkbox" v-model="isChecked1" /> <br />
<!--  v-bind 数据动态绑定 (单向) -->
<!--场景 :  主要用在属性中 -->
<input type="checkbox" :checked="isChecked2" />*

操作样式

1.操作样式

<!-- 1. 静态类名 -->
<h1 class="red">哈哈</h1>
​
<!-- 2. 动态类名 -->
<h1 :class="cls">哈哈</h1>
​
<!-- 3. 最常用 -->
<!-- :class 里的值是一个对象 
      键 : 类名 (可能会要,也可以不要)
      值 : 布尔值, true/false 确定类要不要
     -->
<h1 :class="{ red:isRed , fz:isFZ}">哈哈</h1>
​
<!-- 4. style -->
<h1 :style="{ color : 'red', fontSize : fz + 'px' }">哈哈</h1>

2.其他操作

<!-- 1 -->
<!-- 重点 -->
<div :class="{ active: true }"></div>
===>
<div class="active"></div>
​
<!-- 2 -->
<div :class="['active', 'text-danger']"></div>
===>
<div class="active text-danger"></div>
​
<!-- 3 -->
<div :class="[{ active: true }, errorClass]"></div>
===>
<div class="active text-danger"></div>
​
--- style ---
<!-- 1   -->
<h1 :style="{ color : 'red', fontSize : fz + 'px' }">哈哈</h1>
<!--  fz : 80 -->
​
<!-- 2 将多个 样式对象 应用到一个元素上-->
<!-- baseStyles 和 overridingStyles 都是对象 -->
<!-- 如果有相同的样式,以后面的样式为准 -->
<div :style="[baseStyles, overridingStyles]"></div>

v-on 指令

注册事件/绑定事件

  1. v-on:click 绑定了一个单击事件

    : 后面是事件名称

<button v-on:click="fn">按钮</button>
  1. 缩写 : @click='fn'<button @click='fn'>按钮</button>

  2. 函数写在 methods 里面

fn : function(){ ... }
fn() { ... }
  1. 函数里面的 this 指的就是 vm 实例

> 在函数里面操作数据
- 获取数据  this.msg
- 修改数据  this.msg = 'XXX'
  1. 传参5.1 正常传参

@click='fn(123)'

5.2 事件对象 $event

<!-- 4.1 绑定事件对象的时候, 没有添加小括号,此时,直接在方法中,通过参数 e 就可以获取到事件对象 -->
<!-- 4.2 如果添加小括号,就拿不到事件对象了,vue留了一个$event -->
<button @click="fn1($event,123)">我是按钮</button>

v-for

  1. v-for 指令: 遍历数据,为数据中的每一项生成一个指令所在的标签

  2. 代码

<!-- 需求1 : 最常用 遍历数组 -->
<!-- 作用 : 遍历 list1 数据, 为数据中的每一项生成一个li标签 -->
<!-- item 数组里的每一项元素 -->
<ul>
  <li v-for="(item,index) in list1">{{ item }} - {{ index }}</li>
</ul>
<!-- 需求2 : 遍历元素是对象的数组 -->
<ul>
  <li v-for="item in list2">{{ item.name }} - id:{{ item.id }}</li>
</ul>
​
<!-- 需求3 : 遍历对象 -->
<ul>
  <li v-for="(item,key) in obj">{{ item }}-{{key}}</li>
</ul>
​
<!-- 需求4 : 想要生成10个h1 -->
<h1 v-for="item in 10">我是h1 {{ item }}</h1>

: key

  1. 说明 :Vue 中推荐, 在使用 v-for 的时候,添加 key 属性

  2. 介绍 :就地复用

<!-- 显示组件 -->
<p v-for="(item,index) in list" :key="index">
    {{ item.name}} <input type="text" />
</p>
<!-- 数据 -->
data: { list : [ { id : 1, name : '老罗' }, { id : 2, name : '涛涛' }, { id : 3,
name : '聪聪' } ]
<!-- 演示  -->
vm.list.unshift({id:4,name:'马哥'})
  1. 怎么使用 key

    3.1 如果数组里的元素不是对象,并且又不会改变数组的顺序的话 => :key='index'
    ​
    3.2 如果数组里的元素是对象,,使用对象里的固定属性,并且是唯一, id 
    ​
    3.3 语法 : :key='item.id'
    ​
    3.4 以后,写了v-for之后,立马写好 :key

事件修饰符

  1. .prevent 阻止默认行为

  2. 一般用在 a标签阻止跳转默认行为 , 相当于 : e.preventDefault()

    .prevent 阻止默认行为,调用 event.preventDefault() (常用)
    @click.prevent = 'fn'
  3. 其他不常用事件修饰符 :

    - .stop 阻止冒泡,调用 event.stopPropagation()
    - .capture 添加事件侦听器时使用事件捕获模式
    - .self 只当事件在该元素本身触发时,才会触发事件
    - .once 事件只触发一次

异步 DOM 更新

  1. Vue 中采用了 异步DOM更新 的机制

  2. 什么是异步 DOM 更新

  • 数据发生改变后, vue 没有立即将数据的改变更新到视图中,

  • 而是等到数据不再变化的时候 一次性的 将 数据的改变更新到视图中

     //1. 验证了
     for (let i = 0; i < 1000; i++) {
         this.count++
     }
  1. 为什么是异步 DOM 更新?

  • 性能的考虑

  • 因为对于前端来说, 修改数据进行 DOM 操作是常有的事情,如果频繁操作 DOM,会严重影响页面的加载性能

  • DOM 操作这是前端的性能的瓶颈

  • 比如 : for (let i = 1; i < 10000; i++>) 如果同步 就要重新渲染 1000 次

  1. 验证 异步 DOM 更新 :

 //2. 直接获取data 中的值 ,会立马获取成功
console.log(this.count)
this.count++
console.log(this.count)
​
// 但是 通过dom来获取count的值,因为DOM更新这个count值是异步的,是需要一点时间的
console.log(document.querySelector('h1').innerText);
this.count++;
console.log(document.querySelector('h1').innerText);
  1. 需求 : 在数据更新后,立即获取到更新后的内容???>

    DOM 更新后,会执行 this.$nextTick() 的回调函数,所以能拿到值

// setTimeout(() => {
//      console.log(this.$el.children[0].innerText)
//   }, 1000)
this.$nextTick(() => {
  console.log(this.$el.children[0].innerText) // 100
})

监听 watch

  1. 说明 : Vue 中可以通过 watch 配置项,来监听 vue 实例中数据的变化

  2. 基本使用

    watch: {
        // 监听age属性的数据变化
        // 作用 : 只要age的值发生变化,这个方法就会被调用
        // 第一个参数 : 新值
        // 第二个参数 : 旧值,之前的前
        age(newVal,oldVal){
                console.log('新 :',newVal);
                console.log('旧 :',oldVal);
        }
    }
  1. 基本使用案例 :需求 : 监听用户名文本框字符个数(3-6),并显示格式验证

<input type="text" v-model="name" />
<span v-show="isShow">用户名的字符 在 6-12之间</span> if
  if (newVal.length >= 3 && newVal.length <= 6 ) {
  1. 监听对象 (数组也属于对象)

// data :
 data: {
   obj: {
   name: 'zs'
   }
},
// 组件
<input type="text" v-model="obj.name" />
// 监听
  1. 开始监听对象的属性

// 从对象的角度来监听的
 因为对象和数组都是引用类型,引用类型变量存的是地址,地址没有变,所以不会触发watch
obj:{
    // 深度监听 属性的变化
    deep:true,
    // 立即处理 进入页面就触发
    immediate: true,  
    // 数据发生变化就会调用这个函数  
    handler( newVal ) {
      console.log( newVal.name );
     }
  },
 // 从属性的角度来监听
 'obj.name' ( newVal ) {
      console.log('监听对象的属性',newVal);
 }

其他指令 v-else-if 和 v-else

  1. v-else : 两种情况的

<h1 v-if="age >= 18">成年人</h1>
<h1 v-else>未成年</h1>
  1. v-else-if : 三种以上情况

<h1 v-if="num >= 30">老年人</h1>
<h1 v-else-if="num >= 18 && num < 30">成年人</h1>
<h1 v-else>未成年</h1>

其他指令 v-once

  1. v-once 作用 : 告诉 vue 这个标签中的内容,只需要解析一次即便是数据再发送改变, 那么,这个标签中的内容,也不会被更新

  2. 代码

    比如说第一次登陆先显示登陆一欢迎信息

<p>{{ num }}</p>
<p v-once>带 onece的 {{ num }}</p>

其他指令 v-pre

  1. 添加 v-pre 指令,就是告诉 vue 这段节点中没有指令或表达式,不需要解析这样,Vue 就跳过这一段内容的解析,从而,提升性能

  2. 代码

<p>{{ num }}</p>
<p v-pre>带 v-pre {{ num }}</p>

其他指令 v-cloak

1.代码

<!-- 组件 -->
<h1 v-cloak>{{ msg }}</h1>
<!-- 样式 -->
[v-cloak] { display: none }
<!-- 实例vm前阻塞一下 -->
alert(1)
  1. 分析

// 1.页面为什么会闪???闪是因为页面的内容 由  {{ msg}} ==> 100
// 2. 解决办法 : 使用遮盖
// 2.1 给要遮盖的元素添加一个 v-cloak 指令
// 2.2 使用属性选择器,添加样式
// 2.3 vue 会在解析模板后,将 v-cloak指定,从页面中移除
//  移除指令的时候,{{}} 已经变为对应的数据
  1. 注意 : 演示每次右键打开,不要在当前页面刷新,有缓存的

  2. 如果很多元素都需要遮盖,那么久就给父元素添加这个指令

生命周期函数

  • 所有的 vue 组件,都是 vue 实例, 一个组件对应一个实例,并且接收相同的选项对象(一些根实例特有的选项除外)

  • 实例生命周期也叫做 : 组件生命周期

生命周期介绍

vue 生命周期钩子函数

  • 简单说 : 一个组件(实例) 从开始到最后消灭所经历的各种状态,就是一个组件(实例)的生命周期

  • 生命周期钩子函数的定义 : 从组件被创建,到组件挂在到页面上运行,再到页面关闭组件被销毁,这三个阶段总是伴随着组件各种的事件,这些事件,统称为组件的生命周期函数 (简称 : 钩子函数)

  • 开发人员可以通过 vue 提供的钩子函数,让我们写的代码参与到 vue 的生命周期里面来,让我们的代码在合适的阶段起到相应的作用

注意 :

  1. 注意 : vue 在执行过程中 会自动调用 生命周期钩子函数, 我们只需要提供这些钩子函数即可

  2. 注意 : 钩子函数的名称都是 vue 中规定好的

学习 vue 组件生命周期 学什么?

  1. Vue 内部执行的流程(难)

  2. 钩子函数如何使用 (两个重要的钩子函数 created mounted)

钩子函数 - beforeCreate

  • 说明 : 在实例初始化之前,数据观测 和 event/watcher 事件配置之前被调用

  • 组件实例刚被创建,组件属性计算之前, 例如 data 属性 methods 属性

  • 注意 : 此时,无法获取 data 中的数据 和 methoids 中的方法

  • 场景 : 几乎不用

钩子函数 - created (掌握)

  • 说明 : 组件实例创建完成,属性已绑定, 可以调用 methods 中的方法、可以获取 data 值

  • vue 实例生命周期 参考 1

  • vue 实例生命周期 参考 2

  • 使用场景 : 1-发送 ajax 2-本地存储获取数据

  • beforeCreate() {
        // 无法获取数据和事件
        console.warn('beforeCreate', this.msg, this.fn)
    },
    created() {
      console.warn('created', this.msg, this.fn)
    },

Has 'el' option ?

  1. YES => 就是正常的 el 边界

  2. NO => 可以注释,但是必须要手动添加 vm.$mount(el) 去指定边界

vm.$mount('#app')

Has template option?

  1. No => 将 el 的 outerHtml 作为模板进行编译 ( outerHTML = 自身 + innerHTML )

  2. YES =>

 // 如果提供了 template, 那么 vue 就会将 template 的内容进行编译,编译后,替换页面中 vue 管理的边界
   template : `
      <h1>嘻嘻</h1>
   `,

钩子函数 - beforeMounted()

  • 说明 : 在挂载开始之前被调用 (挂载:可以理解DOM 渲染)

钩子函数 - mounted() (掌握)

  • 说明 : 挂载之后, DOM 完成渲染

  • 使用场景 : 1-发送 ajax 2-操作 DOM

  • 记得把template去掉 
    // 渲染DOM之前
     beforeMount() {
         // 渲染之前的  <h1 id="h1" @click="fn">{{ msg }}</h1>
       console.log(document.querySelector('h1'))
     },
     // 渲染DOM之后  <h1 id="h1">测试</h1>
     mounted() {
       console.log(document.querySelector('h1'))
     }

钩子函数 - beforeUpdated()

  • 说明:数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。

  • 注意:此处获取的数据是更新后的数据,但是获取页面中的 DOM 元素是更新之前的

    小提示 : 打印 this.$el ,打开小三角是之后的,是因为打印是有监听的功能,展示的是后面更改之后的

钩子函数 - updated()

  • 说明:组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。

  • beforeUpdate() {
        // 更新之前的值  :  信息
      console.warn('beforeUpdate',document.querySelector('h1').innerText)
    },
    updated() {
        // 更新之后的值 : 信息1111
      console.warn('updated', document.querySelector('h1').innerText)
    }

钩子函数 - beforeDestroy()

  • 说明:实例销毁之前调用。在这一步,实例仍然完全可用。

  • 使用场景:实例销毁之前,执行清理任务,比如:清除定时器等

  created() {
​
   this.timerId =   setInterval(() => {
      console.log(1111);
​
      }, 500);
   },
​
 // 如果当组件销毁了,还不清除定时器会出现性能问题
 // 在浏览器中可以尝试销毁  vm.$destroy()
 // 最后销毁
beforeDestroy() {
      clearInterval(this.timerId)
 },

钩子函数 - destroyed()

说明:Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。

使用钩子函数来完善 数据存储

created {
    this.list = JSON.parse(localStorage.getItem('list'))
}

使用接口的形式发送数据

json-server 提供假数据接口

  1. json-server 作用 : 根据指定的 JSON 文件, 提供假数据接口

  2. 地址 : json-server

  3. 使用步骤

    1. 全局安装 json-server  : `npm i -g json-server`
    2. 准备一个json数据
    3. 执行 :  `json-server data.json`
    ​
    > json数据参考
    json数据可以参考 :
    {
      "todos": [
        {
          "id": 1,
          "name": "吃饭",
          "age": 20
        }
      ]
    }
  4. REST API 格式

* 1. 查询 : GET
* 2. 添加 : POST
* 3. 删除 : DELETE
* 4. 更新 : PUT 或者 PATCH(打补丁)     

axios 发送请求 (重点掌握)

读音 : /艾克笑丝/

作用 : 一个专门用来发送 ajax 请求的库, 可以在浏览器或者 node.js 中使用

Promise based HTTP client for the browser and node.js
    以Promise为基础的HTTP客户端,适用于:浏览器和node.js
    封装ajax,用来发送请求,异步获取数据

使用步骤

1. 本地安装 axios : `npm i axios`
2. 导入 axios
3. 使用

过滤器

概念 :

  • vue 中的过滤器(filter) : 数据格式化 ,

  • 也就是说,让数据按照我们规定的一种格式输出

  • 比如 : 对于日期来说,将日期格式化转化为 年-月-日 小时:分:秒 格式的过程

 // 直接显示
 <h1>{{ date  }}</h1>
 显示 :   2019-01-11T10:11:19.566Z
 不是我们想要的
 我们想要的 : 2019-01-11 18-11-53

全局过滤器 和 局部过滤器

  • 说明 : 通过全局方式创建的过滤器,在任何一个组件中都可以使用

  • 注意点: 使用全局过滤器的时候,应该先创建全局过滤器,再创建 Vue 实例

  • 局部创建的过滤器 只能在当前 vue组件中使用

  • 怎么注册 全局过滤器

// 第一个参数 : 过滤器的名字
// 第二个参数 : 是一个回调函数,只要使用过滤器的时候,这个回调函数就会执行
///           通过回调函数的返回值得到格式化后的数据
Vue.filter('date', res => {
  return '嘻嘻'
})

过滤器

  1. 概念 :

  • vue 中的过滤器(filter) : 数据格式化 ,

  • 也就是说,让数据按照我们规定的一种格式输出

  • 比如 : 对于日期来说,将日期格式化转化为 年-月-日 小时:分:秒 格式的过程

 // 直接显示
 <h1>{{ date  }}</h1>
 显示 :   2019-01-11T10:11:19.566Z
 不是我们想要的
 我们想要的 : 2019-01-11 18-11-53
  1. 全局过滤器 和 局部过滤器

  • 说明 : 通过全局方式创建的过滤器,在任何一个组件中都可以使用

  • 注意点: 使用全局过滤器的时候,应该先创建全局过滤器,再创建 Vue 实例

  • 局部创建的过滤器 只能在当前 vue组件中使用

  1. 怎么注册 全局过滤器

// 第一个参数 : 过滤器的名字
// 第二个参数 : 是一个回调函数,只要使用过滤器的时候,这个回调函数就会执行
///           通过回调函数的返回值得到格式化后的数据
Vue.filter('date', res => {
  return '嘻嘻'
})
  1. 使用过滤器 示例 :

// 组件
 <h1>时间戳-格式 {{ date2 | date }}</h1>
​
// js
  Vue.filter('date', res => {
         return `${res.getFullYear()}-${res.getMonth()}-${res.getDate()} ${res.getHours()}:${res.getMinutes()}:${res.getSeconds()}`
      })
  1. moment 插件

  • moment 地址

  • 使用

    1. 安装 : `npm i moment`
    2. 引入 :
    3. 使用
  • 日期 => 指定格式 moment(res).format('YYYY-MM-DD HH-mm-ss')

  • 时间戳 => 指定格式 moment(res).format('YYYY-MM-DD HH-mm-ss')

  • // 全局
    Vue.filter('date', res => {
      return moment(res).format('YYYY-MM-DD HH-mm-ss')
    })
  1. 参数问题

  • 示例

<h1>时间戳-格式 {{ date2 | date('YYYY-MM-DD HH-mm-ss',888) }}</h1>
​
// 默认值
Vue.filter('date', (res, format = 'YYYY-MM-DD', arg) => {
  console.log(arg)
  return moment(res).format(format)
})

局部过滤器

在 vm 的配置项里写一个 filters对应的是一个对象

使用过滤器 示例 :

// 组件
 <h1>时间戳-格式 {{ date2 | date }}</h1>
​
// js
  Vue.filter('date', res => {
         return `${res.getFullYear()}-${res.getMonth()}-${res.getDate()} ${res.getHours()}:${res.getMinutes()}:${res.getSeconds()}`
      })

moment 插件

  • moment 地址

  • 使用

    1. 安装 : `npm i moment`
    2. 引入 :
    3. 使用
  • 日期 => 指定格式 moment(res).format('YYYY-MM-DD HH-mm-ss')

  • 时间戳 => 指定格式 moment(res).format('YYYY-MM-DD HH-mm-ss')

  • // 全局
    Vue.filter('date', res => {
      return moment(res).format('YYYY-MM-DD HH-mm-ss')
    })

组件

一 : 组件化开发

  • 概念 :将一个完整的页面,抽离成一个个独立的组件,最终,通过这一个个独立组件完成整个的页面(项目)的功能

  • 组件化开发的优势/作用 : 复用

  • 官网 : 组件是可复用的 Vue 实例

二 : 组件的基本使用

  1. Vue 中的两种注册组件的方法 1.全局注册 2.局部注册

    全局组件在所有的vue实例中都可以使用
    局部组件在所有的当前实例中可以使用

2) 注册全局组件 - 基本使用 1

/**
 * 第一个参数 : 组件名
 * 第二个参数 : 是一个配置对象, 该配置对象与 Vue 实例的配置对象几乎完全相同
 *        也就是说: vue实例中用到的配置项,和组件中的配置项几乎相同
 */
Vue.component('hello', {
  template: `
      <h1 class="red">这是hello组件</h1>
      `
})
  1. 注意点

  • 注册全局组件也是放到 vm 实例之前

  • 模板只有一个根节点

  • 组件的配置项和 vue 实例 的配置项一样 (如:data、methods、filters、watch、computed、钩子函数等)

  • 组件的 data 是一个函数 返回一个对象

      var Component = function() {}
      // 使用对象
      Component.prototype.data = {
        demo: 123
      }
      // 使用函数
      Component.prototype.data = function() {
        return {
          demo: 111
        }
      }
      var component1 = new Component()
      var component2 = new Component()
      component1.data().demo = '8888'
      console.log(component2.data().demo) // 456

示例:

 <h1 @click='fn' class="red">这是hello组件</h1>
  methods: {
          fn() {
            console.log('fn')
          }
        },
        computed: {},
        watch: {},
        filters: {}
}

组件通讯 (介绍)

  • 组件是一个独立、封闭的个体

  • 也就是说 : 组件中的数据默认情况下, 只能在组件内部使用,无法直接在组件外部使用

  • 可以将 vue 实例看做一个组件

  • 对于组件之间需要相互使用彼此的情况,应该使用 组件通讯 机制来解决

  • 组件通讯的三种情况 :

  1. 父组件将数据传递给子组件(父 -> 子)

  2. 子组件将数据传递给父组件 (子 => 父)

  3. 非父子组件(兄弟组件)

父 ==> 子 (重点) 两步

  1. 将要传递的数据,通过属性传递给子组件

<child :msg="pmsg"></child>
  1. 子组件通过 props 配置项,来指定要接收的数据

props: ['msg']

完善 TodoMVC => 完成 传值 + 渲染列表页

子 ==> 父 (重点) 三步

1 父组件中提供一个方法

pfn(arg) {
​
    console.log('父组件中接受到子组件传递过来的数据:', arg)
 }

2 将这个方法传递给子组件

// 自定义事件 <child @fn="pfn"></child>

3 子组件调用这个方法( 触发父组件中传递过来的自定义事件 )

// 这个方法是点击事件触发的
 handleClick() {
    // 调用父组件中的方法 fn
    // 注意:通过 $emit 方法来触发事件 fn
    // 第一个参数:表示要触发的自定义事件名称,也就是 @fn
    // 第二个参数:表示要传递给父组件的数据
    this.$emit('fn', 'child msg')
}

非父子之间通讯 ( 组件 => 组件 ) (重点)

需求 : 组件 jack ===> 恁弄啥哩 ===> 组件 rose

  • 是通过 事件总线 (event bus 公交车) 的机制 来实现的

  • 事件总线 : 实际上就是一个 空Vue实例

  • 可以实现任意两个组件之间的通讯,而不管两个组件到底有什么样的层级关系

  • 看图

  • 示例 :

// 第一步 : 事件总线
var bus = new Vue()
​
// 第二步 : 发送数据   可在点击事件里 触发事件
// 参数1 : 唯一标识  参数2:参数
bus.$emit('todo', '恁弄啥哩?')
​
// 第三步 : 接收数据    可在 created 里 注册事件
bus.$on('todo', arg => {
  console.log('接收过来的', arg)
})

prop 的大小写

  1. 官 : HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。

    html 的标签和 属性 都是一样,忽略大小写<H1 TITLE="哈哈">我是h1</H1>

  2. 官 : 这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名不好使了

  • <child :cMsg="pmsg"></child> 会报警告,父传子也接收不到了

  • 原因是 : 接收的属性是:cMsg, 接收的数据名,因为忽略大小写,数据已为 : cmsg

  • 所以已经准备要读取的 是 cmsg 的值,找不到,所以要报警告You should probably use "c-msg" instead of "cMsg".

  1. 方式 1 : 全用小写,不要使用驼峰命名

    接收 : cmsgprops/读取 :cmsg

  2. 方式 2 官 : 需要使用其等价的 kebab-case (短横线分隔命名) 命名:

    接收 : :c-msg='pmsg'props/读取 : cMsg (一定要注意是 props ,所以只会出现在父传子,不存在子传父里)

路由 (重难点)

  • 路由 : 是浏览器 URL 中的哈希值( # hash) 与 展示视图内容 之间的对应规则

  • 指路

在 web App 中, 通过一个页面来展示和管理整个应用的功能.
SPA 往往是功能复杂的应用,为了有效管理所有视图内容,前端路由 应运而生.
简单来说,路由就是一套映射规则(一对一的对应规则), 由开发人员制定规则.
当 URL 中的哈希值( `#` hash) 发生改变后,路由会根据制定好的规则, 展示对应的视图内容
  • vue 中的路由 : 是 hashcomponent 的对应关系, 一个哈希值对应一个组件

基本使用

    1. 安装路由 : npm i vue-router

    1. 引入路由

    <script src="./vue.js"></script>
    // 千万注意 :引入路由一定要在引入vue之后,因为vue-router是基于vue工作的
    <script src="./node_modules/vue-router/dist/vue-router.js"></script>
    1. 实例路由对象+挂载到 vue 上

    const router = new VueRouter()路由实例 与 Vue 实例 关联到一起验证路由是否挂载成功, 就看打开页面,最后面有没有个 #/

    详细使用步骤 ( 四步骤 )

  • 3.1 入口 (#哈希值)

// 方式1 : url地址为入口   调试开发用
输入url地址 改变哈希值
`01-路由的基本使用.html#/one`
​
// 方式2 : router-link+to
  • 3.2 设置路由规则

// path : 路由路径
// component : 将来要展示的路由组件
routes: [{ path: '/one', component: One }, { path: '/two', component: Two }]
  • 3.3 组件

    一个哈希值对应一个组件

const One = Vue.component('one', {
  template: `
        <div> 子组件 one </div>
        `
})
  • 3.4 出口

<!--  出口 组件要展示的地方-->
<router-view></router-view>

使用注意事项

  1. 入口(哈希)

  • 最常用的入口

<!-- 1. 入口 -->
<!-- 
    to 属性 , 实际上就是哈希值,将来要参与路由规则中进行与组件匹配
    router-link 组件最终渲染为 : a标签, to属性转化为 a标签的href属性
  -->
<router-link to="/one">首页</router-link>
  1. 组件

    组件可以改为对象格式

const One = {
  template: `
        <div> 子组件 one </div>
        `
}
  1. 过程 : 入口 ==> 路由规则 ==> 组件 ==> 出口

  2. 演示 : 多个组件匹配

  3. 示例 :

<div id="app">
  <!-- 1 路由入口:链接导航 -->
  <router-link to="/one">One</router-link>
  <router-link to="/two">Two</router-link>
​
  <!-- 4 路由出口:用来展示匹配路由视图内容 -->
  <router-view></router-view>
</div>
​
<!--  导入 vue.js -->
<script src="./vue.js"></script>
<!--  导入 路由文件 -->
<script src="./node_modules/vue-router/dist/vue-router.js"></script>
<script>
  // 3 创建两个组件
  const One = Vue.component('one', {
    template: '<h1>这是 one 组件</h1>'
  })
  const Two = Vue.component('two', {
    template: '<h1>这是 two 组件</h1>'
  })
​
  // 0 创建路由对象
  const router = new VueRouter({
    // 2. 路由规则
    routes: [
      { path: '/one', component: One },
      { path: '/two', component: Two }
    ]
  })
​
  const vm = new Vue({
    el: '#app',
    //0. 不要忘记,将路由与vue实例关联到一起!
    router
  })
</script>

精确匹配和模糊匹配

  • 精确匹配 : router-link-exact-active 类名 : 只有当 浏览器地址栏中的哈希值 与 router-link 的 to 属性值,完全匹配对,才会添加该类

  • 模糊匹配: router-link-active 类名 : 只要 浏览器地址栏中的哈希值 包含 router-link 的 to 属性值,就会添加该类名

  • 解决办法 : 加个 exact

<router-link to="/" exact>
  One
</router-link>
  • 注意 : 精确匹配和模糊匹配,只对添加类名这个机制有效,与路由的匹配规则无关!!!

猜你喜欢

转载自blog.csdn.net/weixin_44137393/article/details/87969621
今日推荐