Vue入门

目录

前言

1、响应的数据绑定

2、组件系统

2.1响应式原理

2.1组件系统

3、生命周期

4、vuex

附件


 

前言

Vue.js(读音 /vjuː/, 类似于 view)是一个构建数据驱动的 web 界面的库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。

Vue.js 自身不是一个全能框架——它只聚焦于视图层。因此它非常容易学习,非常容易与其它库或已有项目整合。另一方面,在与相关工具和支持库一起使用时,Vue.js 也能完美地驱动复杂的单页应用。

1、响应的数据绑定

 

        Vue.js 的核心是一个响应的数据绑定系统,它让数据与 DOM 保持同步非常简单。在使用 jQuery 手工操作 DOM 时,我们的代码常常是命令式的、重复的与易错的。Vue.js 拥抱数据驱动的视图概念。通俗地讲,它意味着我们在普通 HTML 模板中使用特殊的语法将 DOM “绑定”到底层数据。一旦创建了绑定,DOM 将与数据保持同步。每当修改了数据,DOM 便相应地更新。这样我们应用中的逻辑就几乎都是直接修改数据了,不必与 DOM 更新搅在一起。这让我们的代码更容易撰写、理解与维护。

2、组件系统

        组件系统是 Vue.js 另一个重要概念,因为它提供了一种抽象,让我们可以用独立可复用的小组件来构建大型应用。如果我们考虑到这点,几乎任意类型的应用的界面都可以抽象为一个组件树:

 

     实际上,一个典型的用 Vue.js 构建的大型应用将形成一个组件树。

     你可能已经注意到 Vue.js 组件非常类似于自定义元素——它是 Web 组件规范的一部分。实际上 Vue.js 的组件语法参考了该规范。例如 Vue 组件实现了 Slot API 与 is 特性。但是,有几个关键的不同:

Web 组件规范仍然远未完成,并且没有浏览器实现。相比之下,Vue.js 组件不需要任何补丁,并且在所有支持的浏览器(IE9 及更高版本)之下表现一致。必要时,Vue.js 组件也可以放在原生自定义元素之内。

Vue.js 组件提供了原生自定义元素所不具备的一些重要功能,比如组件间的数据流,自定义事件系统,以及动态的、带特效的组件替换。

      组件系统是用 Vue.js 构建大型应用的基础。另外,Vue.js 生态系统也提供了高级工具与多种支持库,它们和 Vue.js 一起构成了一个更加“框架”性的系统。

      这里简单介绍下vue最常用也较重要的两块:响应式原理和组件系统。

2.1响应式原理

 

如何追踪到到变化

Vue.js采用的则是基于依赖收集的观测机制。从原理上来说,和老牌MVVM框架Knockout是一样的。依赖收集的基本原理是:

1.将原生的数据改造成 “可观察对象”。一个可观察对象可以被取值,也可以被赋值。
2.在watcher的求值过程中,每一个被取值的可观察对象都会将当前的watcher注册为自己的一个订阅者,并成为当前watcher的一个依赖。
3.当一个被依赖的可观察对象被赋值时,它会通知所有订阅自己的watcher重新求值,并触发相应的更新。
4.依赖收集的优点在于可以精确、主动地追踪数据的变化,不存在上述提到的脏检查的两个问题。但传统的依赖收集实现,比如Knockout,通常需要包裹原生数据来制造可观察对象,在取值和赋值时需要采用函数调用的形式,在进行数据操作时写法繁琐,不够直观;同时,对复杂嵌套结构的对象支持也不理想。

Vue.js利用了ES5的Object.defineProperty方法,直接将原生数据对象的属性改造为getter和setter(这是ES5的特性,需要js解释引擎的支持,无法通过各种打shim补丁来实现,至少现在的babel pollyfill和各种shim是没法的。这也是为什么Vue不支持IE8及以下版本的原因,因为IE8的defineProperty只支持DOM对象,纯Object会报错。),在这两个函数内部实现依赖的收集和触发,而且完美支持嵌套的对象结构。对于数组,则通过包裹数组的可变方法(比如push)来监听数组的变化。这使得操作Vue.js的数据和操作原生对象几乎没有差别[注:在添加/删除属性,或是修改数组特定位置元素时,需要调用特定的函数,如obj.$add(key, value)才能触发更新。这是受ES5的语言特性所限。在操作对象类型数据的时候一定要注意这点,否则无法实现响应。

变化检测问题

受 ES5 的限制,Vue.js 不能检测到对象属性的添加或删除。因为 Vue.js 在初始化实例时将属性转为 getter/setter,所以属性必须在 data 对象上才能让 Vue.js 转换它,才能让它是响应的。例如:

var data = {a : 1}

var vm = new Vue({

    data : data

})

//vm.a 和 data.a 现在是响应的

 

vm.b = 2

//vm.b 不是响应的

 

data.b = 2

//data.b 不是响应的

对于 Vue 实例,可以使用 $set(key, value) 实例方法:

vm.$set('b'2)

//vm.b 和 data.b 现在是响应的

对于普通数据对象,可以使用全局方法 Vue.set(object, key, value):

Vue.set(data, 'c'3)

//vm.c 和 data.c 现在是响应的

有时你想向已有对象上添加一些属性,例如使用 Object.assign() 或 _.extend() 添加属性。但是,添加到对象上的新属性不会触发更新。这时可以创建一个新的对象,包含原对象的属性和新的属性:

// 不使用 Object.assign(this.someObject, {a : 1,b : 2})

this.someObject = Object.assign({}, this.someObject, {a : 1, b : 2})

异步更新队列

可能还没有注意到,Vue 异步执行 DOM 更新。只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会一次推入到队列中。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作上非常重要。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际(已去重的)工作。Vue 在内部尝试对异步队列使用原生的 Promise.then 和 MutationObserver,如果执行环境不支持,会采用 setTimeout(fn, 0) 代替。

    例如,当设置 vm.someData = 'new value' ,该组件不会立即重新渲染。当刷新队列时,组件会在事件循环队列清空时的下一个“tick”更新。多数情况不需要关心这个过程,但是如果你想在 DOM 状态更新后做点什么,这就可能会有些棘手。虽然 Vue.js 通常鼓励开发人员沿着“数据驱动”的方式思考,避免直接接触 DOM,但是有时我们确实要这么做。为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用 Vue.nextTick(callback) 。这样回调函数在 DOM 更新完成后就会调用。例如:

<div id="example">{{message}}</div>

var vm = new Vue({

  el: '#example',

  data: {

    message: '123'

  }

})

vm.message = 'new message' // 更改数据

vm.$el.textContent === 'new message' // false

Vue.nextTick(function () {

  vm.$el.textContent === 'new message' // true

})

在组件内使用 vm.$nextTick() 实例方法特别方便,因为它不需要全局 Vue ,并且回调函数中的 this 将自动绑定到当前的 Vue 实例上

计算属性的奥秘

你应该注意到 Vue.js 的计算属性不是简单的 getter。计算属性持续追踪它的响应依赖。在计算一个计算属性时,Vue.js 更新它的依赖列表并缓存结果,只有当其中一个依赖发生了变化,缓存的结果才无效。因此,只要依赖不发生变化,访问计算属性会直接返回缓存的结果,而不是调用 getter。

为什么要缓存呢?假设我们有一个高耗计算属性 A,它要遍历一个巨型数组并做大量的计算。然后,可能有其它的计算属性依赖 A。如果没有缓存,我们将调用 A 的 getter 许多次,超过必要次数。

由于计算属性被缓存了,在访问它时 getter 不总是被调用。考虑下例:

var vm = new Vue({

    data : {

        msg : 'hi'

    },

    computed : {

        example : function (){

            return Date.now() + this.msg

        }

    }

})

  计算属性 example 只有一个依赖: vm.msg 。 Date.now()  不是 响应依赖,因为它跟 Vue 的数据观察系统无关。因而,在访问  vm.example  时将发现时间戳不变,除非  vm.msg  变了。

有时希望 getter 不改变原有的行为,每次访问  vm.example  时都调用 getter。这时可以为指定的计算属性关闭缓存:

computed : {

    example : {

        cache : false,

        get : function (){

            return Date.now() + this.msg

        }

    }

}

现在每次访问  vm.example  时,时间戳都是新的。但是,只是在 JavaScript 中访问是这样的;数据绑定仍是依赖驱动的。如果在模块中这样绑定计算属性  {{example}} ,只有响应依赖发生变化时才更新DOM。

计算属性不可在data里面定义,如果定义会报错:变量不可被重复定义和赋值; 应用场景:一个数据受多个数据影响

 

侦听器watch

首先确认 watch是一个对象,一定要当成对象来用。 
对象就有键,有值。 
键:就是你要监控的那个家伙,比如说$route,这个就是要监控路由的变化。或者是data中的某个变量。 
值可以是函数:就是当你监控的家伙变化时,需要执行的函数,这个函数有两个形参,第一个是当前值,第二个是变化后的值。 
值也可以是函数名:不过这个函数名要用单引号来包裹。 
第三种情况厉害了。 
值是包括选项的对象:选项包括有三个:

  1. handler:其值是一个回调函数。即监听到变化时应该执行的函数。

  2. deep:其值是true或false;确认是否深入监听。(一般监听时是不能监听到对象属性值的变化的,数组的值变化不需要使用deep)

  3. immediate:其值是true或false;确认是否以当前的初始值执行handler的函数。

    var vm = new Vue({

      data: {

        a: 1,

        b: 2

      },

      watch: {

        a: function (val, oldVal) {

          console.log('new: %s, old: %s', val, oldVal)

        },

        // 方法名

        b: 'someMethod',

        // 选项的对象

        c: {

          handler: function (val, oldVal) { /* ... */ },

          deep: true

          immediate: true

        }

      }

    })

    data里面需要定义;应用场景:一个数据影响多个数据

     

     


2.1组件系统

          组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以是原生 HTML 元素的形式,以 is 特性扩展。

1、导入组件

import ComponentA from './ComponentA'

import ComponentC from './ComponentC'

 

export default {

  components: {

    ComponentA,

    ComponentC

  },

  // ...

}

现在 ComponentA 和 ComponentC 都可以在 ComponentB 的模板中使用了。

2、props

组件A 使用组件B ,那么A组件和B组件的关系就是父子关系,父组件通过props向子组件传递数据

//子组件定义prop

Vue.component('blog-post', {

  props: ['title'],

  template: '<h3>{{ title }}</h3>'

})

 

 

//父组件引用

<blog-post title="My journey with Vue"></blog-post>

 

3、props类型

 

props: {

  title: String,

  likes: Number,

  isPublished: Boolean,

  commentIds: Array,

  author: Object

}

4、props验证

        我们可以为组件的 prop 指定验证要求,例如你知道的这些类型。如果有一个需求没有被满足,则 Vue 会在浏览器控制台中警告你。这在开发一个会被别人用到的组件时尤其有帮助。

为了定制 prop 的验证方式,你可以为 props 中的值提供一个带有验证需求的对象,而不是一个字符串数组。例如:

props: {

    // 基础的类型检查 (`null` 匹配任何类型)

    propA: Number,

    // 多个可能的类型

    propB: [String, Number],

    // 必填的字符串

    propC: {

      type: String,

      required: true

    },

    // 带有默认值的数字

    propD: {

      type: Number,

      default100

    },

    // 带有默认值的对象

    propE: {

      type: Object,

      // 对象或数组默认值必须从一个工厂函数获取

      default: function () {

        return { message: 'hello' }

      }

    },

    // 自定义验证函数

    propF: {

      validator: function (value) {

        // 这个值必须匹配下列字符串中的一个

        return ['success''warning''danger'].indexOf(value) !== -1

      }

    }

}

5、.sync修饰符

在说vue 修饰符sync前,我们先看下官方文档:vue .sync 修饰符,里面说vue .sync 修饰符以前存在于vue1.0版本里,但是在在 2.0 中移除了 .sync 。但是在 2.0 发布之后的实际应用中,我们发现 .sync 还是有其适用之处,比如在开发可复用的组件库时。我们需要做的只是让子组件改变父组件状态的代码更容易被区分。从 2.3.0 起我们重新引入了 .sync 修饰符,但是这次它只是作为一个编译时的语法糖存在。它会被扩展为一个自动更新父组件属性的 v-on 监听器。

示例代码如下:

<comp :foo.sync="bar"></comp>

当子组件需要更新 foo 的值时,它需要显式地触发一个更新事件:

this.$emit('update:foo', newValue)

猛一看不明白,下边我么通过一个实例(弹窗的关闭事件)来说明这个代码到底是怎么运用的。

<template>

    <div class="details">

        <myComponent :show.sync='valueChild' style="padding: 30px 20px 30px 5px;border:1px solid #ddd;margin-bottom: 10px;"></myComponent>

        <button @click="changeValue">toggle</button>

    </div>

</template>

<script>

import Vue from 'vue'

Vue.component('myComponent', {

      template: `<div v-if="show">

                    <p>默认初始值是{{show}},所以是显示的</p>

                    <button @click.stop="closeDiv">关闭</button>

                 </div>`,

      props:['show'],

      methods: {

        closeDiv() {

          this.$emit('update:show'false); //触发 input 事件,并传入新值

        }

      }

})

export default{

    data(){

        return{

            valueChild:true,

        }

    },

    methods:{

        changeValue(){

            this.valueChild = !this.valueChild

        }

    }

}

</script>

vue 修饰符sync的功能是:当一个子组件改变了一个 prop 的值时,这个变化也会同步到父组件中所绑定。如果我们不用.sync,我们想做上面的那个弹窗功能,我们也可以props传初始值,然后事件监听,实现起来也不算复杂。这里用sync实现,只是给大家提供一个思路,让其明白他的实现原理,可能有其它复杂的功能适用sync。

这只是一个简单的例子,看完这个不知你是不觉得有个指令跟这个很相似,v-model?对,就是v-model在组件上使用的时候。
具体的可以查看:vue 自定义组件使用v-model,可以实现同样的功能。也是以这个弹窗事件做演示的

6、父子组件/兄弟组件的通信

       父子组件:由于prop是父组件向子组件传递的单项数据流,所以子组件想要更改父组件的值,可以用到下面的方法

  • 使用  $on()  监听事件;

  • 使用  $emit()  在它上面触发事件;

      兄弟组件:可以使用数据总线来传递数据,具体方法是先实例化一个空的vue对象,如下:

import Vue from 'vue'

export default new Vue()

使用的时候在相应的组件里:import bus from 'xxx',

  • 使用bus.$on监听事件
  • 使用bus.$emit在它上面出发事件

7、动态组件

多个组件可以使用同一个挂载点,然后动态地在它们之间切换。使用保留的  <component> 元素,动态地绑定到它的 is 特性,is绑定的是组件导入进来的名字

<component :is="currentView">

    <!-- 组件在 vm.currentview 变化时改变 -->

</component>

如果把切换出去的组件保留在内存中,可以保留它的状态或避免重新渲染。为此可以添加一个  keep-alive  指令参数:

<component :is="currentView" keep-alive>

    <!-- 非活动组件将被缓存 -->

</component>

应用场景:1、组件动态切换;2、有些 HTML 元素,诸如 <ul>、<ol>、<table> 和 <select>,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li>、<tr> 和 <option>,只能出现在其它某些特定的元素内部。

 

3、生命周期

可以看到在vue一整个的生命周期中会有很多钩子函数提供给我们在vue生命周期不同的时刻进行操作, 下面是所有生命周期钩子函数及应用场景:

生命周期钩子

组件状态

最佳实践

beforeCreate实例初始化之后,this指向创建的实例,不能访问到data、computed、watch、methods上的方法和数据常用于初始化非响应式变量
created实例创建完成,可访问data、computed、watch、methods上的方法和数据,未挂载到DOM,不能访问到$el属性,$ref属性内容为空数组常用于简单的ajax请求,页面的初始化
beforeMount在挂载开始之前被调用,beforeMount之前,会找到对应的template,并编译成render函数-
mounted实例挂载到DOM上,此时可以通过DOM API获取到DOM节点,$ref属性可以访问常用于获取VNode信息和操作,ajax请求
beforeupdate响应式数据更新时调用,发生在虚拟DOM打补丁之前适合在更新之前访问现有的DOM,比如手动移除已添加的事件监听器
updated虚拟 DOM 重新渲染和打补丁之后调用,组件DOM已经更新,可执行依赖于DOM的操作避免在这个钩子函数中操作数据,可能陷入死循环
beforeDestroy实例销毁之前调用。这一步,实例仍然完全可用,this仍能获取到实例常用于销毁定时器、解绑全局事件、销毁插件对象等操作
destroyed实例销毁后调用,调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁-

4、vuex

         在大型应用中,状态管理常常变得复杂,因为状态分散在许多组件内,在不同的作用域内。以vue来说,当使用vue-router以及组件化开发(.vue)来构建大型单页应用的时候,组件之间状态的数据的传递会很困难,虽然props、emit等能够进行跨组件的数据传递,但是大量使用它们会使组件之间的耦合程度很高,组件越多,层级越多,维护起来就越复杂。怎么办呢?能否在全局提供一个状态管理构架?

什么是Vuex?

  官方说法:Vuex 是一个专为 Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

  个人理解:Vuex是用来管理组件之间通信的一个插件

       vuex 包含有五个基本的对象:

  • state:存储状态。也就是变量;
  • getters:派生状态。也就是set、get中的get,有两个可选参数:state、getters分别可以获取state中的变量和其他的getters。外部调用方式:store.getters.personInfo()。就和vue的computed差不多;
  • mutations:提交状态修改。也就是set、get中的set,这是vuex中唯一修改state的方式,但不支持异步操作。第一个参数默认是state。外部调用方式:store.commit('SET_AGE', 18)。和vue中的methods类似。
  • actions:和mutations类似。不过actions支持异步操作。第一个参数默认是和store具有相同参数属性的对象。外部调用方式:store.dispatch('nameAsyn')
  • modules:store的子模块,内容就相当于是store的一个实例。调用方式和前面介绍的相似,只是要加上当前子模块名,如:store.a.getters.xxx()

附件

vue组件官方文档   :https://cn.vuejs.org/v2/guide/components-registration.html

vuex官方文档   : https://vuex.vuejs.org/zh/guide/state.html

vuex谷歌插件:Vue.js devtools

vue-demo  :  https://github.com/PanJiaChen/vue-element-admin.git

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值