内容字号:默认大号超大号

段落设置:段首缩进取消段首缩进

字体设置:切换到微软雅黑切换到宋体

Vue实例

2019-03-06 11:18 出处:清屏网 人气: 评论(0

在刚接触Vue的时候,就知道 实例 在Vue中是一个重要的概念,在学习之后也整理了一篇有关于 Vue实例和生命周期的学习笔记 。经过一段时间的学习之后,重新再温习了一遍有关于Vue的实例,整理一下,提供给有需要的同学作为参考资料。

Vue 的基本原理

Vue是一个优势的JavaScript框架,其主要是用来处理 视图层 (我的理解就是UI层)。当用户操作 View Model (即JavaScript,在Vue中指的是Vue实例,一个观察者)使其依照一定的逻辑取得需要改变的数据( Model ),配合在HTML中Vue提供的模板语法来改变配置,重新渲染后使画面产生相应的变化( View )。用一张图来描述这个过程:

比如我们在浏览器中渲染出来的页面有个 区域 和“删除”按钮,当用户点击“删除”按钮之后,会移除这个区域。用户交互之后反馈给用户的是,界面(视图)中的区域被移除。看上去非常的简单,其实在Vue中,主要经历了以下几个过程:

  • (1) 用户在界面中点击“Remove”按钮进行交互
  • (2) 通过模板中的绑定触发Vue实例中注册的 remove() 事件
  • (3) remove() 事件通过 Ajax 向服务器请求数据
  • (4) 服务器取得的数据后重新传给Vue实例
  • (5) Vue实例修改绑定的ViewModel
  • (6) ViewModel改变后触模板重新渲染
  • (7) 改变后的视图反馈给用户(用户看到重新渲染后的视图)

咱们可以用下图来描述这个交互的整个过程:

事实上Vue的原理要比这复杂的多,只不过用上图来阐述对于初学者而言在概念上有一定的辅助作用。但其也遵循一个原则: 视图的状态由数据描述,并且通过数据来驱动视图变化

深入的概念还无法理解的情况之下,我们暂时只需要先记住,在Vue中视图和数据之间的关系是一个非常简单的关系,即 双向数据绑定

Vue采用发布者 —— 订阅者模式实现双向数据绑定,首先Vue将会获得需要监听的对象的所有属性,通过 Object.defineProperty 方法完成对象属性的劫持,将其转化为 gettersetter ,当属性被访问或修改时,立即将变化能知给订阅者,并由订阅者完成相应的逻辑操作。

我们可以用下图来描述双向数据绑定主要流程:

  • Observer :主要处理属性监听逻辑,将监听属性转化为 getset 属性,当属性被访问时,调用 dep.depend() 方法,而属性被修改时,则调用了 dep.notify() 方法
  • Dep :担任发布者的角色,维护访问者列表,负责订阅者的添加和通知工作,上面所提到的 depend()notify() 方法在这里实现
  • Watcher :担任订阅者角色,即 Dep.target ,可以订阅多个 Dep ,在每次收到发布者消息通知时触发 update() 方法执行更新逻辑

创建Vue实例

接下来,我们来创建一个Vue实例,就是前面提到的 ViewModel 部分。Vue实例是Vue中很重要的一部分,创建他很简单:

let app = new Vue({

})

创建Vue实例很简单,通过 new Vue({}) 即可。事实上,Vue实例就是一个JavaScript对象,而且常常将这个对象赋值给一个 app 变量。

Vue的第一个参数是 options ,它会传给Vue实例这个对象。 options 这个参数主要包括:

  • el :Vue实例需要挂载的一个DOM元素,一般是 index.html 文件中的 div#app 元素
  • data :需要一个输出取得结果的数据
  • methods :方法
  • Vue实例生命周期的钩子函数

比如下面这个示例:

let app = new Vue({
    el: '#app',
    data () {
        return {
            message: 'W3cplus.com'
        }
    },
    methods: {
        getRemoteMessage () {
            Promise.resolve('获取远程数据:大漠')
                .then((res) => {
                    this.message = res
                })
        }
    }
})

除了上面这种方式,Vue实例的挂载还有另外一种方式:

// main.js
new Vue({
    render: h => h(App),
}).$mount('#app')

而给Vue实例传递参数,可以像下面这样的方式:

<!-- App.vue -->
<script>
    export default {
        name: 'app',
        data () {
            return {
                message: 'W3cplus.com'
            }
        },
        methods: {
            getRemoteMessage () {
                Promise.resolve('获取远程数据:大漠')
                    .then((res) => {
                        this.message = res
                    })
            }
        }
    }
</script>

上面的示例主要做了三件事情:

  • 将Vue实例挂载在页面中 idapp 的一个 div 元素上
  • data 中初始化了一个 message ,并且在 <template> 中以 {{message}} 方式将 data 中的 message 显示在页面上
  • 定义了一个 getRemoteMessage() 方法,该方法会以非同步的方式取得 message
  • <template> 中的一个 button 绑定了定义好的 getRemoteMessage() 方法
  • 当用户点击界面中的按钮,将会获取远程的一个数据,并且更改 <template>message 的值

效果如下:

创建一个Vue实例就是这么的简单。

最开始我们也提到了,Vue实例是Vue中重要的部分之一,甚至可以说, 任何一个Vue的应用程序都是从Vue实例开始的,大创建实例后,可以通过操作实例中的参数来改变页面的配置

以上示例代码可以查阅 app-vue-instance 项目的 step1 分支。

Vue实例的生命周期

Vue实例中还有另一个重要的内容,那就是Vue实例的生命周期,在Vue实例中会在各个生命周期中提供相应的钩子函数(Hooks事件),这些钩子函数让开发者可以在Vue实例阶段做相应的处理。Vue官方为Vue实例的生命周期提供了一张非常详细的图:

上图展示了Vue实例整个生命周期,其中红框白底就是生命周期中具备的钩子函数:

  • beforeCreate :Vue实例初始化的时候会立即调用,其发生在未创立Vue实例之前,这个时候在Vue实例中的设置都还未配置完成,比如 data
  • created :Vue实例创建完成,此时Vue实例中的配置除了 $el 外全部配置,而 $el 只有在Vue实例挂载到相应的HTML元素时才会生效
  • beforeMount :在Vue实例挂载到目标元素之前被调用,这时的 $el 会是还未被Vue实例中的定义渲染的初始设定的模板
  • mounted :Vue实例上的设置已经安装上模板,这里的 $el 是已经由实例中的定义渲染成真成的页面
  • beforeUpdate :当Vue实例中的 data 发生变化后或是执行 vm.$forceUpdate() 调用,这时的页面还未被重新沉浸而改变页面
  • updated :在重新渲染页面后被调用,这时的页面已经被重新渲染成改变后的页面
  • beforeDestroy :Vue实例被销毁前调用,这个时候Vue实例还是拥有完整的功能
  • destroyed :Vue实例被销毁,这个时候Vue实例中的任何定义都已被解除绑定,此时对Vue实例做的任何操作都会失效

接下来看一个小示例,把分支切换到 step2 ,来看看Vue实例中操作各个钩子函数,然后打印出 data$el ,看看在各个钩子函数中它们是如何变化的。

<!-- App.vue -->
<template>
    <div id="app">
        <img alt="Vue logo" src="./assets/logo.png">
        <h2>{{ message }}</h2>
        <div>
            <button @click="getRemoteMessage">获取远程数据</button>
        </div>
    </div>
</template>

<script>
    export default {
        name: 'app',
        data () {
            return {
                message: 'W3cplus.com'
            }
        },
        methods: {
            getRemoteMessage () {
                Promise.resolve('获取远程数据:大漠')
                    .then((res) => {
                        this.message = res
                    })
            }
        }
    }
</script>

根据上图,将Vue实例生命周期中的钩子函数分成四组:

  • beforeCreate created :创建Vue实例
  • beforeMount mounted :挂载目标元素
  • beforeUpdate updated :改变后重新渲染
  • beforeDestroy destroyed :销毁Vue实例

beforeCreatecreated

先来看 beforeCreatecreated 两个钩子函数,在Vue实例中添加这两个钩子函数,打印出相应的 data$el

beforeCreate () {
    console.log(`>>> ==== 钩子函数 beforeCreate ==== >>>`)
    console.log(`this.message: ${this.message}`)
    console.log(`this.$el: ${this.$el}`)
    console.log(`>>> ==== End ==== >>>`)
},
created () {
    console.log(`>>> ==== 钩子函数 created ==== >>>`)
    console.log(`this.message: ${this.message}`)
    console.log(`this.$el: ${this.$el}`)
    console.log(`>>> ==== End ==== >>>`)
}

结果如下:

由于 beforeCreate 阶段,Vue实例还没有创建,所以 message$el 都是 undefined ;而到了 created 阶段时,Vue实例已经创建了,所以 message 变成了 W3cplus.com ,但 $el 因为还没有挂载到目标元素,所以依旧是 unddefined

也就是说, beforeCreate 钩子中是不能对Vue实例中的任何东西做操作

beforeMountmounted

和前面的方式一样,在Vue实例中添加钩子函数 beforeMountmounted

beforeMount () {
    console.log(`>>> |_==_| 钩子函数 beforeMount |_==_| >>>`)
    console.log(`this.message: ${this.message}`)
    console.log(`this.$el: ${this.$el}`)
    console.log(`>> |_==_| this.$el.outerHTML 开始 |_==_| >>`)
    console.log(this.$el.outerHTML)
    console.log(`>> |_==_| this.$el.outerHTML 结束 |_==_|`)
    console.log(`>>> |_==_| End |_==_| >>>`)
},
mounted () {
    console.log(`>>> |_==_| 钩子函数 mounted |_==_| >>>`)
    console.log(`this.message: ${this.message}`)
    console.log(`this.$el: ${this.$el}`)
    console.log(`>> |_==_| this.$el.outerHTML 开始 |_==_| >>`)
    console.log(this.$el.outerHTML)
    console.log(`>> |_==_| this.$el.outerHTML 结束 |_==_| >>`)
    console.log(`>>> |_==_| End |_==_| >>>`)
}

结果如下:

在Vue实例的流程图中提到,开始执行 beforeMount 钩子函数时,此时 $el 还没有生成HTML到页面上,因此在执行 this.$el.outerHTML 时会报警,如上图所示。而在执行 mounted 钩子函数时,Vue实例已经绑定到元素上,所以这里看到的是渲染后的结果。

也就是说, beforeMount 前同样不能操作DOM元素

beforeUpdateupdated

同样的,把 beforeUpdateupdated 钩子函数加入到Vue实例中:

beforeUpdate () {
    console.log(`>>> (^_^) 钩子函数 beforeUpdate (^_^) >>>`)
    console.log(`this.message: ${this.message}`)
    console.log(`this.$el: ${this.$el}`)
    console.log(this.$el.outerHTML)
    console.log(`>>> (^_^) End (^_^) >>>`)
},
updated () {
    console.log(`>>> (^_^) 钩子函数 updated (^_^) >>>`)
    console.log(`this.message: ${this.message}`)
    console.log(`this.$el: ${this.$el}`)
    console.log(this.$el.outerHTML)
    console.log(`>>> (^_^) End (^_^) >>>`)
}

当你点击页面上的按钮时,打印出来的结果如下:

beforeDestroydestroyed

beforeDestroy () {
    console.log(`(^_^) 钩子函数 beforeDestroy (^_^)`)
    console.log(`this.message: ${this.message}`)
    console.log(`this.$el:${this.$el}`)
    console.log(this.$el.outerHTML)
    console.log(`(^_^) End (^_^)`)
},
destroyed () {
    console.log(`(^_^) 钩子函数 destroyed (^_^)`)
    console.log(`this.message: ${this.message}`)
    console.log(`this.$el:${this.$el}`)
    console.log(this.$el.outerHTML)
    console.log(`(^_^) End (^_^)`)
}

第一次执行 app.__vue__.$destroy() 会打印出相应的信息,再执行一次将会报错,如下图所示:

正如上面所示,执行 beforeDestroy 后,即将执行销毁Vue实例,如果想要释放一些资源,可以在这里操作;当执行 destroyed 时,Vue实例将会销毁。比如上面的示例,执行 app.__vue__.$destroy() 后,再点击页面上的按钮,不会有任何的反应,这是因为我们的Vue实例已销毁。

小结

本文从Vue的基本原理着手,学习了Vue的一些基本原理以及相关的概念,然后学习Vue实例的创建以及Vue实例生命周期中的钩子函数,并通过简单的实例,演示了Vue实例中不同钩子函数时实例的状态。这样对于学习Vue实例以及生命周期就不仅仅是停在概念上的,而是知道每个不同周期中对应钩子函数中具体的行为。这样一来,在实际使用Vue的时候,更能清楚的什么事情该在什么样的钩子函数中执行,才能起到相应的效果。特别是对于DOM的操作,掌握这些尤其重要。


分享给小伙伴们:
本文标签: Vue

相关文章

发表评论愿您的每句评论,都能给大家的生活添色彩,带来共鸣,带来思索,带来快乐。

CopyRight © 2015-2016 QingPingShan.com , All Rights Reserved.