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 中:首先考虑的是微任务(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
optimize:优化(静态化)(标记静态节点,可以使patch的时候直接跳过静态资源,直接拿来用)
generate:ast转化为字符串
确实是有点小乱,有点碎,现在只是记录一下