第二节:Vue实例化
1.创建一个Vue实例
通过vue函数创建一个新的vue实例
一个 Vue 应用由一个通过new Vue创建的 根 Vue 实例 ,以及可嵌套的、可复用的组件树组成的。
我们先看看Vue基本的使用,至于组件我们后面详细的在来探讨
divid="app"!-- {{ 插值表达式,可以赋值 取值 三元 }} --{{ msg }}/divscriptsrc="./node_modules\vue\dist\vue.js"/scriptscript// 引入vue后 会白给你一个Vue构造函数letvm=newVue({// 配置对象el:'#app',// 告诉vue能管理那个部分,使用的是querySelectordata:{// data中的数据会被vm所代理msg:'hello world',// 可以通过vm.msg取到对应的内容 ,也可以赋值 }})/script
2.声明式渲染
Vue.js 的核心是一个允许采用简洁的模板语法来声明式地将数据渲染进 DOM 的系统:
2.1. 关于{{}} 插值表达式
插值表达式,表达式,赋值运算,计算,三元表达式,但是尽量少在这里写逻辑计算
插值:
!-- HTML ---divid="app"{{ message }}/div!-- JS ---scriptnewVue({el:'#app',data:{messgae:'hello Vue!'}})/script
我们已经成功创建了第一个 Vue 应用!看起来这跟渲染一个字符串模板非常类似,但是 Vue 在背后做了大量工作。现在数据和 DOM 已经被建立了关联,所有东西都是响应式的。我们要怎么确认呢?
如果需要确定现在的数据是否已经和DOM建立了关联,形成响应式.
可以将js中的new Vue复制给一个全局变量vm.此时vm就是Vue实例化对象,未来可能会用它来搞很多事情,但是最常用到它的时候,是通过this关键字来使用它
varvm=newVue({el:'#app',data:{messgae:'hello Vue!'}})
然后在浏览器的js控制台中修改vm.message值,同时页面也会发生改变
在控制台中输入
vm.messge="你好,Vue"
2.2.使用 JavaScript 表达式
迄今为止,在我们的肆卖模板中,我们一直都只绑定简单的属性键值。但实际上,对于所有的数据绑定,Vue.js 都提供了完全的 JavaScript 表达式支持。
{{ number + 1 }}{{ ok ? 'YES' : 'NO' }}{{ message.split('').reverse().join('') }}divv-bind:id="'list-' + id"/div
这些表达式会在所属 Vue 实例的数据作用域下作为 JavaScript 被解析。
示例:
divid="app"!-- 数字操作 --p{{ number + 2 }}/p!-- 三目运算 --p{{ ok ? 'YES' : 'NO' }}/p!-- 字符串翻转 --p{{ message.split('').reverse().join('') }}/p/divscriptconstvm=newVue({el:"#app",data:{message:'Hello World',number:10,ok:true,}})/script
显示结果:
1.png
但是有个限制就是,每个绑定双大括号(Mustache语法)里面都只能包含 单个表达式
2.3. 关于data数据
vue关注的是数据变化,不需要在像裂桥逗以前一样关注DOM的变化
比如我想在2秒之后让页面发生消或变化,我们只需要在2秒后更改数据就可以了
varvm=newVue({el:'#app',data:{msg:'hello world'}})setTimeout(function(){vm.$data.msg="bye world"},2000)
关于实例介绍:
示例中vm是Vue的实例对象,
实例对象上有$data属性,其值就是选项对象中data属性值
选项对象就是在实例化Vue时传入的对象
data属性值是一个对象,因此$data也就是这个对象
当通过$data修改msg的值时,也就等于改data中的值, 对应是引用类型
因此示例的结果就是:
2秒后data数据中msg的值改变了, 又因为Vue是始终在关注着msg这个数据,一旦数据发生变化,就会触发Vue的响应式, 继而改变视图显示
2.4 再次理解MVVM模式
在上一节讲Vue的mvvm模式的时候就有提到,
Vue实例对象就是vm,data数据就是model, 页面显示的结果就是view
再来看一下mvvm的图
mvvm.jpg
这张图在配合刚才的示例, 我们就能很好的理解,当数据Model发生变化以后, Vue就可以通过Data Bindings了解到,然后使用新的数据去改变页面显示
至于Vue如何通过DOM Listeners监听页面的改变,来改变数据,这个我们之后讲到在说
3.实例上的方法
除了数据属性,Vue 选项对象中还暴露了一些有用的属性与方法。在通过实例对象使用选项对象的属性时,属性前面都需要带上前缀$,以便与用户定义的属性区分开来。例如:
vardata={a:1}varvm=newVue({el:'#example',data:data})vm.$data===data// = truevm.$el===document.getElementById('example')// = true
3.1. 实例上常用的属性和方法
vm.$attrs// 用户获取父组件传递给子组件的属性,(除props,class,style外)vm.$data// vm 上的数据vm.$watch// 监听vm.$el// 当前el元素vm.$set// 后加的属性实现响应式vm.$options// vm 配置 上的 所有属性vm.$nextTick(()={})// 异步方法,等待渲染dom完成后来获取vmvm.$refs// 获取dom元素或者组件实例的引用
其实我们可以创建一个Vue实例,然后在控制台上打印这个实例对象,你会看到很多的属性和方法
constvm=newVue({el:"#app",})
在控制台输入vm
显示结果:
实例属性.png
这里面很多属性,我们暂时不用去关心他,因为随着学习的深入,慢慢都会学习到的.
4.实例化多个vue
我们可以在页面上同时实例化多个Vue, 不同的实例接管页面上不同的区域.
看下如下的示例:
## h1实例化多个Vue对象/h1divid="app-one"h2{{ title }}/h2p{{ greet }}/p/divdivid="app-two"h2{{ title }}/h2p{{ greet }}/pbuttonv-on:click="changeTitle"点击改变app-one的h2的内容/button/divscript// Vue实例varone=newVue({el:'#app-one',data:{title:" vue-app-one的内容"},computed:{greet:function(){return"Hello App One"}}})// Vue实例vartwo=newVue({el:'#app-two',data:{title:" vue-app-two的内容"},methods:{changeTitle:function(){one.title="app-one的内容发生改变了"}},computed:{greet:function(){return"Hello App two"}}})/script
Vue事件和方法还没有讲到, 先做一个了解即可:
示例分析:
两个实例one和two接管了不同的DOM元素,
点击按钮是在two实例接管的DOM元素中,
所以,当你点击时,只会触发two实例中的方法, 也只会改变two实例中的数据
那么问题来了?
能否在two实例中修改one实例中的数据呢,?
答案当然是可以的啦, 因为变量one是全局变量,
在two实例化中,就可以通过one变量得到第一个Vue实例化对象,
然后就可以通过实例化对象修改数据,这个可以自己尝试写写.
5. Vue 操作DOM元素
虽然Vue是数据驱动的,但是有的时候我们就需要自己手动的获取到DOM元素,对DOM元素进行操作,那么该如何处理呢,
操作DOM元素:
在需要操作的DOM元素中使用ref属性,
ref属性的值是自己随便定义的名字
通过Vue实例的$refs属性获取操作dom元素
divid="app"divref="wuwei"无为/div/divscriptvarvm=newVue({// 根实例el:'#app',data:{},mounted(){//dom元素中有多个一样的ref,dom如果不是通过v-for循环出来的,只能获取一个// 如果是循环出来的,可以获取多个,获取的是一个数组console.log(this.$refs.wuwei)}});/script
关于示例中$refs属性的解释:
因为可以在多个DOM元素上使用ref.
所以$refs属性获取的是所有具有ref属性的DOM元素的集.
因此要想操作确定的DOM元素就需要在通过当初的ref值获取.
简而言之: 就是ref在dom元素上通过this.$refs.自定义名字是获取dom元素
当获取到DOM元素后,然后就可以采用原生的JavaScript对DOM进行操作
注意:
Vue 接管的DOM元素之外的元素使用ref是获取不了的,值是undefined
vue生命周期详解
vue源码中最终执行生命周期函数都是调用 callHook 方法, callHook 函数的逻辑很简单友山,根据传入的生命周期类型 hook ,去拿到 vm.$options[hook] 对应的回调函数数组,然后遍历执行,执行的时候把 vm 作为函数执行的上下文。
1. new Vue(options) :创建一个vm实例;
2. mergeOptions(resolveConstructorOptions(vm.constructor), options, vm) :合并Vue构造函数里options和传入的options或合并父子的options。比如:在mergeOptions函数中会调用mergeHook方法合并生命周期的钩子函数,mergeHook方法原理是只有父时返回父,只有子时返回数组类型的子。父、子都存在时,将子添加在父的后面返回组合而成的数组。这也是父子均有钩子函数的时候,先执行父的后执行缺埋子的的原因;
3. initLifecycle(vm)、initEvents(vm)、initRender(vm) :在创建的vm实例上初始化生命周期、事件、渲染相关的属性;
4. callHook(vm, 'beforeCreate') :调用beforeCreate生命周期钩子函数;
5. initInjections(vm)、initState(vm)、initProvide(vm) :初始化数据:inject、state、provide。initState 的作用是初始化 props、data、methods、watch、computed 等属性;
6. callHook(vm, 'created') :调用created生命周期钩子函数;
7. vm.$mount(vm.$options.el) : $mount 方法在多个文件中都有定义,如"src/platform/web/entry-runtime-with-compiler.js"、"src/platform/web/runtime/index.js"、"src/platform/weex/runtime/index.js"。因为 $mount 方法的实现是和平台、构建方式相关的。以"entry-runtime-with-compiler.js"为例,关键步骤是查看 vm.$options 中是否有伏告蚂render方法,如果没有则会根据el和template属性确定最终的template字符串,再调用 compileToFunctions 方法将template字符串转为render方法,最后,调用原先原型上的$mount方法,即开始执行"lifecycle.js"中 mountComponent 方法;
8. callHook(vm, 'beforeMount') :调用beforeMount生命周期钩子函数;
9. vm._render() = vm._update() = vm.__patch__() :先执行vm._render方法,即调用createElement生成虚拟DOM,即VNode ,每个VNode有children ,children 每个元素也是⼀个 VNode,这样就形成了⼀个 VNode Tree;再调用vm._update方法进行首次渲染,vm._update方法核心是调用vm. patch 方法,这个方法跟vm.$mount一样跟平台相关;vm. patch 方法则是根据生成的VNode Tree递归createElm方法创建真实Dom Tree挂载到Dom上;
10. callHook(vm, 'mount') :调用mount生命周期钩子函数:VNode patch 到 Dom 之后会执行 'invokeInsertHook'函数,把 insertedVnodeQueue 中保存的mount钩子函数执行一遍,insertedVnodeQueue队列中的钩子函数是在根据VNode Tree递归createElm方法创建真实Dom Tree过程生成的钩子函数顺序队列,因此mounted钩子函数的执行顺序是先子后父;
11. data changes :数据更新,nextTick中执行 flushSchedulerQueue 方法,该方法会执行watcher队列中的watcher;
12. callHook(vm, 'beforeUpdate') :执行watcher时会执行watcher的before方法,即调用beforeUpdate生命周期钩子函数;
13. Virtual DOM re-render and patch :重新render生成新的Virtual DOM,并且patch到DOM上;
14. callHook(vm, 'updated') :调用updated生命周期钩子函数;
15. vm.$destroy() :启动卸销毁过程;
16. callHook(vm, 'beforeDestroy') :调用beforeDestroy生命周期钩子函数;
17. Teardown watchers, childcomponents and event listeners :执行一系列销毁动作,在 $destroy 的执行过程中,它又会执行 vm.__patch__(vm._vnode, null) 触发它子组件的销毁钩子函数,这样一层层的递归调用,所以 destroyed 钩子函数执行顺序是先子后父,和 mounted 过程一样。
18. callHook(vm, 'destroyed ') :调用destroyed 生命周期钩子函数。
Vue实例理解
Vue实例是通过Vue函数来创建的。可以传入一个选项对象。一个Vue应用通过创建一个根Vue实例,以及可以嵌套和可复用的组件树组成。可以看出,Vue应用实际上是由组件树组成。
Vue实例被创建时,它将data对象中的所有property加入到Vue响应系统中。当这些property属性值发生改变含散时,视图更新为新的值。
定义一个对象,赋值给data对象,修改定义的对象的原始数据,也会改变property的值。
数据改变,视图会重渲染,只有当实例被创建时就以及存在于data中的property才是逗老颤响应的。因此, 也就解释了为什么需要在property时定义初始值 ,这样当发生数据改变会山败更新。
Vue实例自身暴露了一些有用的实例property与方法,它们都有前缀 el(表示挂载的元素),vm. watch()等。
以上内容为新媒号(sinv.com.cn)为大家提供!新媒号,坚持更新大家所需的前端知识。希望您喜欢!
版权申明:新媒号所有作品(图文、音视频)均由用户自行上传分享,仅供网友学习交流,不声明或保证其内容的正确性,如发现本站有涉嫌抄袭侵权/违法违规的内容。请发送邮件至 k2#88.com(替换@) 举报,一经查实,本站将立刻删除。