vue行走之路

    因为项目需要,所以需要学习,虽然理解不是很深,但是还是简单的记录一下。
    vue是一个前端开发框架,是一个mvvm模式框架,侧重于vm(视图模型)部分,同时具备了angular和react的优点,又很轻量,所以经常用在一些项目开发中。
    借用官方的一句话来说就是vue是一套构建用户界面的渐进式框架,是一个构建数据驱动的 web 界面的库,也可以理解为是一个视图模板引擎,强调的是状态到界面的映射,数据发生变化时,界面也一起发生改变。
    渐进式框架,我比较倾向于理解为自由,vue它本身并不是一个全面的框架,而是专注于视图层,那么我们在最基本的声明式渲染(视图模板引擎)上,可以随时的按照开发需求去添加组件系统、客户端路由、大规模状态管理来构建一个完整的框架,让我们可以按需单独的添加某个部分的功能,而不需要将所有都加载进来,使得开发更加自由。
    这就是vue的设计理念,渐进式,也是vue的使用方式。

vue生命周期

    首先我们先来一张图来简单了解一下


2399431513-59cb0ac1e91b1_articlex.png

    从图中我们可以知道vue的生命周期大概是这样的 创建-监控-初始化-编译-替换-挂载-销毁
    我们先来简单的了解一下,在这个声明周期中vue做了哪些工作
1、创建一个vue对象
2、开始监控data对象数据变化
3、vue内部初始化事件
4、对模板进行编译,把这些模板编译成一个渲染函数Render,然后render函数调用createElement方法创建并且返回一个虚拟DOM树
5、通过patch函数去进行虚拟DOM树和真实DOM的比对,从而将虚拟DOM上的变化添加到真实DOM上
6、监控数据变化,实时更新DOM
7、销毁组件上所有的监听,引用等
8、销毁组件

    上面讲到,vue会对数据源进行监控,并实时更新到DOM,这个涉及到了双向数据绑定的原理,我们会在下面讲到。

    vue的生命周期过程中还涉及到了众多生命周期钩子方法,由于版本不同,我们这边也引用一张图来显示

3346068135-580822cd52898_articlex.png

    从上图可以看出,2.0对比于1.0来说基本上的钩子方法都差不多,比1.0多出了beforeUpdate、updated、activated、deactivated这四个钩子方法
    这里就不一一列举各个钩子方法的具体使用方式了,大家有兴趣可以到官网进行了解https://cn.vuejs.org/v2/api/

双向数据绑定原理以及实现
1、原理

    vue的双向数据绑定主要是依靠于Object.defineProperty(),我们来看看MDN上对这个方法的定义

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
该方法允许精确添加或修改对象的属性。通过赋值操作添加的普通属性是可枚举的,能够在属性枚举期间呈现出来(for...in 或 Object.keys 方法), 这些属性的值可以被改变,也可以被删除。这个方法允许修改默认的额外选项(或配置)。默认情况下,使用 Object.defineProperty() 添加的属性值是不可修改的。

    Object.defineProperty(obj, prop, descriptor)这个方法有3个参数,分别是obj(定义属性的对象)、prop(定义或者修改的属性的名称)、descriptor(被定义或者修改的属性描述符)
obj跟prop都是字面上的意思,下面需要讲的是descriptor这个参数
    descriptor有两个主要的形式:数据描述符和存取描述符。

数据描述符和存取描述符均具有以下可选键值:
    configurable
    当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认为 false
    enumerable
当且仅当该属性的enumerable为true时,该属性才能够出现在对象的枚举属性中。默认为 false

数据描述符同时具有以下可选键值:
    value
    该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为undefined
    writable
    当且仅当该属性的writable为true时,value才能被赋值运算符改变。默认为 false

存取描述符同时具有以下可选键值:
    get
    一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。当访问该属性时,该方法会被执行,方法执行时没有参数传入,但是会传入this对象(由于继承关系,这里的this并不一定是定义该属性的对象)。默认为undefined
    set
    一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。当属性值修改时,触发执行该方法。该方法将接受唯一参数,即该属性新的参数值。默认为undefined

    要注意的一点是:在 descriptor 中不能同时设置访问器(get 和 set)和 wriable 或 value,否则会错,就是说想用 get 和 set,就不能用 writable 或 value 中的任何一个。

2、实现

    descriptor 的其他属性我们可以不必太关注,我们主要关注的重点是set和get这两个方法,我们来看一个简单的实例:

<body>
    <div id="app">
        <input type="text" id="ipt">
        <p id="show-text"></p>
    </div>
    <script>
        var obj = {}
        var ipt = document.getElementById('ipt')
        var showText = document.getElementById('show-text')
        Object.defineProperty(obj, 'text', {
            get: function () {
                return obj
            },
            set: function (newValue) {
                ipt.value = newValue
                showText.innerHTML = newValue
            }
        })
        ipt.addEventListener('keyup', function (e) {
            obj.text = e.target.value
        })
    </script>
  </body>

    在这个实例里,我可以随时获取输入框中的值,并在set函数中将这个值设置到obj对象中,包括我要获取所要显示的值,也是去obj对象中拿到并显示在视图中,由数据来驱动视图的更新,这个是不是很熟悉,这个就是vue的双向数据绑定了。

vue组件

    vue组件是吧UI结构映射到恰当的组件树


20170215102019940.png

一个组件的创建基本上如下所示:

Vue.component('button-counter', {
  data: function () {
    return {
      count: 0
    }
  },
  template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})

    这里是在全局中定义了一个名为button-counter的组件,组件中的数据就是data所返回的对象中的数据,组件模板就是template。然后我们就可以在项目中各处去使用这个组件了,是的,各处,这表示你可以按照需求进行组件嵌套,这就是全局注册的特点。当然,你也可以在局部去注册组件,但是这里就不详细讲了。除了像这样注册组件之外,vue还可以利用构建工具去配置单文件组件,每一个文件里都有 template, script 和 style这三个功能块,使我们可以更加方便的去管理所有的组件。

要点:组件间的父子通信(单向传递)
    父组件可以通过props去向子组件传值,而子组件没有办法直接去传值给父组件,子组件想要跟父组件通信,就需要通过$emit去派发一个自定义事件到父组件中。然后父组件去在子组件标签上监听自定义事件,从而达到子组件向父组件通信的目的,具体的实现可以去参考我的另一篇文章《Vue2.0中父子组件间通信》

    除了父子组件通信之外,还有兄弟组件的通信,不过兄弟组件的通信也是基于父子组件通信上实现的,通过A子传父,父再传B子,在A子传父的基础上,让父组件去使用B子的方法,从而实现A子改变B子的状态。

vue状态管理

    我们在小型项目中可能还可以利用父子组件通信和兄弟组件通信去管理数据,但是在涉及到较多的数据交互的时候,再用那种办法显然就不合适了,vue也提出了一个状态管理的办法去对数据源进行管理,使得我们在多个组件中可以去使用同一个状态,并且只需要维护一份数据就可以。


state.png

    重要的是,注意你不应该在 action 中 替换原始的状态对象 - 组件和 store 需要引用同一个共享对象,mutation 才能够被观察
    组件不允许直接修改属于 store 实例的 state,而应执行 action 来分发 (dispatch) 事件通知 store 去改变。
    如果一个一个的去实现的话,会不会很麻烦呢?所幸,我们有vuex,每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同:
    1、Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
    2、你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
这就很方便了

    我们在store文件中通过Vue.use方法去使用了Vuex,然后new 了一个Vuex.Store对象,在里面声明了state、getters、mutations和actions,并将这个对象返回,然后在根实例中注入,然后就可以在各个组件中去使用了,我们可以在组件中引入mapMutations去设置store 中的state中对应的数据,也可以通过引入mapGetters去获取对应的数据,相关的代码如下:

store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
Vue.use(Vuex)
const store = new Vuex.Store({
    state: {
        select: false
    },
    getters: {
        select: state => state.select
    },
    mutations: {
        setSelect(state, select){
            if (!state.select) {
                state.select = select
            }
        }
    },
    actions: {
    }
})
export default store

入口文件main.js

import Vue from 'vue'
import App from './App'
import store from './store'

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

在子组件A中设置select的状态
A.vue

import { mapMutations } from 'vuex'
 export default {
    name: ' A',
    methods: {
        changeSelected(select) {
          this.setSelect(select)
        }
    },
    ...mapMutations({
        'setSelect'
    })
}

在子组件B中去获取
B.vue

import { mapGetters } from 'vuex'
export default {
    name: 'B',
    computed: {
      ...mapGetters([
        'select'
      ])
    },
    created() {
      console.log(this.select)
    }
  }

参考文献


https://blog.csdn.net/wmwmdtt/article/details/55095420
https://segmentfault.com/a/1190000011962150
https://segmentfault.com/a/1190000008010666

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容