Vue(一)

353 阅读5分钟

1. sync  和 v-model  的异同

v-model   通常用于表单控件(子组件有更强控制能力,父组件传给子组件的事件名称和属性都由子组件自己决定)---语法糖

<Input v-model="username">
// 默认相当于
<Input :value="username" @input='username=$event'>
//可以通过设置model选项修改默认行为(子组件内)
{
    model: {
        prop: 'checked',
        event:'change'
    }
}
//这样的设置,v-model变化时,则
<checkBox :checked="model.check" @change="model.remember=$event"></checkBox>

// 我的理解,即上面的v-model执行时候,实际上,组件进行的变化为(属性上,为checked,事件上是change事件)

sync   用于修改传递到子组件的属性,控制属性名的权利在父组件

子组件想修改父组件传过来的属性时,可用sync

<Input :value.sync="model.username" >
//等同于
<Input :value="username" @update:value='username=$event'>
<input @input="$emit('update:value', $event)"/> 

<!-- 这里绑定属性名称更改,相应的属性名也会变化 --> <Input :foo="username" @update:foo="username=$event"> 

 

2. 递归组件

在自己的模板中调用自身组件

其中比较重要的是,需要设置name属性,在调用嵌套的时候,需要有条件的使用,不然,可能会造成死循环

<template>   
 <div id="de">        
<h5>默认的页面</h5>
//条件(例)v-if  或者  v-for        、
<Default v-if='msg'></Default>    
</div>
</template>
<script>    
export default {
        name: 'default',
//important        
data() {           
 return { 
               msg          
  }       
 },   
 }</script>
//一般tree 组件,会用到    数据结构,children和父亲一样

3. router

  • Vue.use(Router)

install----->挂载了$router,注册组件

router  的作用:

① 解析路由配置

② 响应url变化

③ 事件监听haschange

④ 组件切换

  • 动态路由

可以在路由的path上配置:

{
   path: '/login/:id',    name: 'login',    component: Login}

此时可以在子组件内直接访问

<p>{{$route.params.id}}</p>


4. 输出格式说明

  • cjs    webpack1,browserfiry
  • esm   webpack2+
  • umd    兼容cjs和amd
  • runtime   仅包含运行时,没有编译器

5. vue

入口文件是:platforms/web/entry-runtime-with-compiler--------其中的作用是覆盖$mount

web运行时:palatforms/web/runtime/index   ----主要实现了$mount------$mount  _patch_

全局api定义:core/global-api/index

Vue构造函数:core/insatnce/index  

-----initMixin()  实现init()(core/instance/iniy.js)----initLifecycle    initEvents  initRender  beforeCreate   initInjections  initProvide  created

-----stateMixin

-----eventsMixin

-----lifecycleMixin

-----renderMixin

过程:挂载,编译,触发渲染函数,依赖收集(首次初始化的时候,渲染并执行挂载)

数组只有这七种方法可以直接改变值:push,shift,unshift,pop,sort,splice,reverse

其他情况则需要set(获取下标不可)

6.vue的特别琐碎的信息

  • vue异步更新:dep.notify()  watcher.update()   queueWatcher()  nextTick()    timerFunc()    watcher.run()
当一次变量多次变化,但nextTick()  只有一次的时候, queueWatcher()  会执行很多次(去重),但watcher.run() 只会执行一次

nextTick 中:首先考虑的是微任务(promise、mutationobserver),其次选setImmediate,最后选setTimeout

  • depIds 和 newDepIds  的作用是保存依赖和去重
  • 一个定时器里面有两个属性变化的处理过程---->属性发生改变,dep通知,watcher更新
  • 定义组件更新函数(updateComponent)

            _render()  获得虚拟dom  vnode           _update()   将虚拟dom转化为真实的dom

//scr/instance/lifecycle.js
updateComponent = () => {
      vm._update(vm._render(), hydrating)
    }

  • 组件更新          

在_update中对新老节点进行判断,然后利用patch函数进行处理

首先同级节点会进行比较,只进行增删改,利用打补丁(_patch_)

第一种情况:当初始化的时候,传入的是真实的dom,拿出之前的元素,再找出其父元素,在父元素中创建出一个新的节点(老节点的旁边),完成之后,删除老的节点

//  dist/vue.runtime.js
oldVnode = emptyNodeAt(oldVnode);//将真实的节点转化为虚拟dom

第二种情况:更新(dist/vue.runtime.js)

key:是判断两个节点是不是同一个节点(不是唯一的因素,例如标签)

属性更新props,文本更新,子节点更新(子节点和文本是冲突,只存在其一)

若是静态资源,直接跳过,节约性能

① 如果新老VNode都是静态的,则只需要替换elm以及componentInstance

② 若新老节点均有children子节点,则需要对子节点进行diff操作,调用updateChildren

遍历向中间靠拢,当其中的  endindex>startindex 时结束     

首先在新老两组vnode节点的左右头尾两侧都有一个变量标记,在便利过程中这几个变量都会向中间靠拢,先比较首位是否一致,一致则打补丁,再遍历第二位,若不相同则从末位继续开始进行比较,若末位相同,则打补丁继续利用前一位进行比较。若新的结束了老的未结束,则为删除,若老的结束了,新的未结束,则为新增。若首尾比较不满足条件的话,则该新节点与老节点一一进行比对(遍历老节点),若无则该节点是新增节点。若满足的话,将oldvnode移动到对应的位置,继续遍历

③ 如果老节点没有子节点而新节点存在子节点,则先清空老节点dom的文本内容,然后将当前dom节点加入子节点

④  如果新节点没有子节点而老节点存在子节点时,则移除该dom节点的所有子节点

⑤ 当新老节点都无子节点时,只需要进行文本的替换

  • 组件  创建是先父后子(创建父组件的时候会顺道创建子组件  src/core/vdom/create-element.js ),挂载是先子后父
组件:执行实例的创建与挂载--->插入到父元素---->元素属性创建

全部都挂载完成之后,再回显展示页面

  • 模板编译:将模板template转换成渲染函数render
parse:将字符串转化成ast(js对象,类似于vnode)

optimize:优化(静态化)(标记静态节点,可以使patch的时候直接跳过静态资源,直接拿来用)

generate:ast转化为字符串


确实是有点小乱,有点碎,现在只是记录一下