手把手,从无到有带你用vue进行项目实战 系列三(深入剖析vue篇)

相关链接:

手把手,从无到有带你用vue进行项目实战 系列一(搭建框架篇)

手把手,从无到有带你用vue进行项目实战 系列二(cdn、gzip性能加速篇)


对Vue的解析主要分为简介、核心内容、组件、路由和状态管理四部分

一、简介

Vue.js主要有四个特点

  • 简单小巧 : Vue.js压缩后只有17k
  • 渐进式 : 可以一步步有阶段的使用而不必一开始使用所有东西
  • 响应式 : 保持视图和状态同步
  • 组件化 : 与react类似,一切都是组件

知识点 : Vue.js如何实现数据双向绑定?

Vue.js的响应式使用起来很简单,不需要引入太多的新概念,声明实例new Vue({data:data})后对data里面的数据进行视图上的绑定。修改data数据,视图中相应数据也会随之修改。

详析

Vue 使用基于依赖追踪的观察系统并且异步队列更新,所有的数据变化都是独立触发,除非它们之间有明确的依赖关系。 vue.js 采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

该方法允许精确添加或修改对象的属性。通过赋值来添加的普通属性会创建在属性枚举期间显示的属性(for...in 或 Object.keys 方法), 这些值可以被改变,也可以被删除。这种方法允许这些额外的细节从默认值改变。

扫描二维码关注公众号,回复: 2775598 查看本文章

知识点 : 数组更新检测注意事项

由于vue检测到数组更新后会触发视图更新,因此单独列出来

变异方法(mutating method 改变原数组)
    push(), pop(), shift(), unshift(), splice(), sort(), reverse() 
非变异 (non-mutating method) 
    filter(), concat() 和 slice() 

注意:
由于 JavaScript 的限制,Vue 不能检测以下变动的数组:
	1.	当你利用索引直接设置一个项时,例如:vm.items[indexOfItem] = newValue
	2.	当你修改数组的长度时,例如:vm.items.length = newLength
为了解决第一类问题,以下两种方式都可以实现和 vm.items[indexOfItem] = newValue 相同的效果,同时也将触发状态更新:
// Vue.set
Vue.set(example1.items, indexOfItem, newValue)
// Array.prototype.splice
example1.items.splice(indexOfItem, 1, newValue)
为了解决第二类问题,你可以使用 spliceexample1.items.splice(newLength)

知识点 : 对象更改注意事项

还是由于 JavaScript 的限制,Vue 不能检测对象属性的添加或删除:
var vm = new Vue({
  data: {
    a: 1
  }
})
// `vm.a` 现在是响应式的

vm.b = 2
// `vm.b` 不是响应式的
对于已经创建的实例,Vue 不能动态添加根级别的响应式属性。
但是,可以使用 Vue.set(object, key, value) 方法向嵌套对象添加响应式属性

总结:使用Vue.js可以让开发更简单,同时颠覆了传统前端开发模式,提供现代web开发中常见对功能:

  • 解耦视图与数据
  • 可复用的组件
  • 前端路由
  • 状态管理
  • 虚拟DOM

二、核心内容

Vue.js具有渐进式的特点,核心部分实现基础功能,路由、状态管理和对服务的封装使用插架,这一部分我们主要解析核心内容

1、生命周期

每个 Vue 实例在被创建之前都要经过一系列的初始化过程。例如需要设置数据监听、编译模板、挂载实例到 DOM、在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,给予用户机会在一些特定的场景下添加他们自己的代码。常用的钩子有:

  • created :实例创建完成后调用,$el还不可用,用于初始化处理数据
  • mounted :el挂载后调用,第一个业务逻辑从这里开始
  • updated :组件更新时调用
  • beforeDestroy : 实例销毁前调用,用于解绑addEventListener监听事件

2、数据绑定

模版语法:
<a :href=“url">...</a>

<a @click="doSomething">...</a>

上面对语法是对v-bind和v-on的缩写,是一个语法糖,实现的结果是一样的。

知识点 : 过滤器

Vue支持在{{}}插值的尾部添加一个管道符“|”对数据进行过滤,经常用于格式化文本,格式如下:

<div>{{ date | formatDate}}</div>
var app = new Vue({
    ...
    filters:{
        formatDate:function(value){
            ...
        }
    }
})

过滤器也可以串联,而且可以使用参数

//串联
{{ message | filter1 | filter2}}
//接收参数
{{message | filterA('arg1','arg2')}}

敲黑板 : vue2新变化

  • 取消了所有内置过滤器
  • 取消了对v-model和v-on的支持,过滤器只能在{{}}中使用
  • 修改了过滤器参数对使用方式,采用函数的方式而不是空格

3、计算属性和观察者

  • Computed:当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch——特别是如果你之前使用过 AngularJS。然而,通常更好的做法是使用计算属性而不是命令式的 watch 回调。
  • Watch:当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

计算属性是依赖它的缓存的,一个计算属性所依赖的数据发生变化时,它才会重新取值,所以只要依赖属性不改变,就不更新。

4、内置指令

  • 4.1 v-cloak :用于解决初始化慢导致页面闪动的问题
<div v-cloak>
    {{message}}
</div>
<style>
    [v-cloak]{
        display:none;
    }
</style>

对于简单的项目很实用,但是在工程化的项目中,项目的HTML文件只有一个空的div元素,剩余内容都是用路由挂在不同组件完成的,所以不需要v-cloak。

  • 4.2 v-if、v-else-if、v-else、v-show

知识点 : v-if与v-show的区别

v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。

v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。

一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

  • 4.3 v-text、v-html
都需要绑定在某个元素上,避免未编译前的闪现问题,用于绑定更新text和innerHtml
  • 4.4 v-el
为dom元素注册了一个索引,可以直接访问dom元素

<div v-el:demo>this is a demo</div>
vm.$els.demo.innerHtml // "this is a demo"

这个不难理解,类似于jquery通过id、class、dom属性获取dom元素
  • 4.5 v-ref
与v-el类似,只不过用于子组件上,实例可以通过$refs访问子组件
  • 4.6 v-once
Vue.js2中的新增指令,表示只渲染一次,及时数据更新也不改变

5、组件

代码复用一直是软件开发中长期存在的问题,每个开发者都想利用之前写好的代码,又担心引入后对现有项目有影响。现在web component的出现提供一种思路,可以自定义tag标签,拥有自己的模版、样式和交互。angular.js的指令、react.js的组件化都在往这个方向尝试,vue.js也提供了自己的组件系统。

组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以表现为用 is 特性进行了扩展的原生 HTML 元素。 所有的 Vue 组件同时也都是 Vue 的实例,所以可接受相同的选项对象 (除了一些根级特有的选项) 并提供相同的生命周期钩子。

  • 5.1 工作流程

在 Vue 中,父子组件的关系可以总结为 prop 向下传递,事件向上传递。父组件通过 prop给子组件下发数据,子组件通过事件给父组件发送消息。看看它们是怎么工作的。

  • 5.2 prop

组件实例的作用域是孤立的。这意味着不能 (也不应该) 在子组件的模板内直接引用父组件的数据。父组件的数据需要通过 prop 才能下发到子组件中。

Vue.component('child', {
  // 在 JavaScript 中使用 camelCase
  props: ['myMessage'],
  template: '<span>{{ myMessage }}</span>'
})
<!-- 在 HTML 中使用 kebab-case -->
<child my-message="hello!"></child>
如果你使用字符串模板,则没有这些限制。

知识点 : props的单向数据流和数据验证

5.2.1 单向数据流 --> vue2新特性

尽可能将父子组件解耦,避免子组件无意中修改了父组件的状态。如果需要使用父组件传过来的数据,有两种方式:

1. 在子组件内再次声明一个参数,引用父组件的prop
2. 使用计算属性

5.2.2props数据验证

验证prop的类型,可以有这几种:String、Number、Boolean、Object、Array、Function

  • 5.3 event
使用 v-on 绑定自定义事件
每个 Vue 实例都实现了事件接口,即:
	•	使用 $on(eventName) 监听事件
	•	使用 $emit(eventName) 触发事件

知识点 : vue2废弃了$dispatch和$broadcast方法

vue2废弃了$dispatch和$broadcast方法,这两种方法主要依赖组件的树结构, 如果组件越来越复杂时,这种结构很难被理解。

  • 5.4 slot

props和event用于分发数据,slot用于分发内容,实例如下:

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>
......
......
<app-layout>
  <h1 slot="header">这里可能是一个页面标题</h1>

  <p>主要内容的一个段落。</p>
  <p>另一个主要段落。</p>

  <p slot="footer">这里有一些联系信息</p>
</app-layout>
......
......
<div class="container">
  <header>
    <h1>这里可能是一个页面标题</h1>
  </header>
  <main>
    <p>主要内容的一个段落。</p>
    <p>另一个主要段落。</p>
  </main>
  <footer>
    <p>这里有一些联系信息</p>
  </footer>
</div>

知识点 : 组件在vue2中的变化

  • event:vue2中废弃了event选项,所有的事件通过$emit、$on和$off来触发、监听和取消监听。另外,废弃了$dispatch和$broadcast方法,这两种方法主要依赖组件的树结构,如果组件越来越复杂时,这种结构很难被理解。
  • keep-alive不再是动态组件component标签中的属性,而是一个单独的标签,也可以单独包裹多个子组件,只要其中一个激活就可以。
  • slot:每个slot只能使用一次。
  • refs:子组件索引的声明方式改变了,不再是一个指令,而替换成特殊的属性 
     <comp ref="first"><comp> //vue.js1中为 <comp v-ref="first"><comp> 

三、路由

vue的路由是独立于核心模块之外的,对于大多数单页面应用,都推荐使用官方支持的 vue-router 库。

vue的路由交给vue-router实现和管理,随着vue升级到vue2,vue-router也做了相应的升级,在适配vue2的同时,自身的使用方法上也做了改变(shit)。

vue-router的基础功能这里不做过多的介绍,主要分析vue-router2的新功能:

知识点 : vue-router2的新升级

vue-router2的新升级主要涉及五个方面:使用方式、跳转方式、钩子函数、获取数据、命名视图,这里主要介绍钩子函数和获取数据

1、钩子函数

1.1 全局钩子

  • beforeEach : 路由切换前调用
  • afterEach : 路由切换后调用

1.2 单个路由钩子

  • beforeEnter

1.3 组件内钩子

  • beforeRouteEnter
  • beforeRouteLeave
钩子实例:

router.beforeEach((to, from, next) => {
   if(window.localStorage.getItem('token')){
	next();
}else{
	next("/login");
}
});

to: 即将要进入的目标的路由对象
from: 当前导航即将要离开的路由对象
next: 调用该方法后,才能进入下一个钩子

2、获取数据

直接来看一下实例:

export default{
	data(){
	        return{
	            ...
	        }
	},
	created(){
	        //组件创建完后获取数据
	        this.fetchData();
	},
	watch:{
	        //如果路由有变化会再次执行该方法
	        '$store':'fetchData'
	},
	methods:{
	        fetchData(){
 //调用service获取数据
}
	}
}

上面的实例就是利用生命周期在不同的时间点获取、刷新数据。

四、状态管理

vue 的状态管理有两种方式:中央事件总线和vuex,这是主要介绍vuex,因为vuex更适合工程化的项目,实现的方式更为优雅。

1、vuex可用于非父子组件(也就是跨级组件和兄弟组件)间通信

  • State:存储数据
  • Mutations:改变store中数据
  • Getters:filter store中的数据
  • Actions:异步改变store中数据
  • Modules:分割多个vuex代码
实例代码:
State:存储数据
const store = new Vuex.store({
	state:{
	        count:0;
	}
});
             在任何的组件内,可以直接调用$store.state.count来获取:
//index.vue
<template>
	<div>
        <h1>首页</h1>
        {{$store.state.count}}
	</div>
</template>

五、异步调用接口数据

axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端

  • 从浏览器中创建 XMLHttpRequest
  • 从 node.js 发出 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求和响应数据
  • 取消请求
  • 自动转换JSON数据
  • 客户端支持防止 CSRF/XSRF
实例:
import axios from ‘axios';
const ajaxUrl = env === 'development'
    ? 'http://10.10.10.10:1212/'
    : 'http://newservice:1100/';
const ajaxFun = function(serviceUrl,paramData,callback){	
	axios({
		method:'post',
		url:serviceUrl,
	    baseURL: ajaxUrl,
	    timeout: 30000,
	    headers: {'content-type': 'application/json'},
	    data:paramData,
	}).then(function(res){
		return callback(res.data);
	}).catch(function (error) {
		var data = {
			retCode:"000000",
			retMsg:"网络错误,请联系客服"
		}
		callback(data);
  	});
}

相关链接:

手把手,从无到有带你用vue进行项目实战 系列一(搭建框架篇)

手把手,从无到有带你用vue进行项目实战 系列二(cdn、gzip性能加速篇)

猜你喜欢

转载自blog.csdn.net/franktaoge/article/details/78803394
今日推荐