VUE学习笔记

目录

vue简介

特点

  • 更加轻量20kb min + gzip
  • 渐进式框架
  • 响应式的更新机制
  • 学习成本低

react35kb,anglar60kb;不需要学习vue的所有知识就可以用于项目开发,可以一步步慢慢学;当数据改变,视图会自动刷新;模板语法是基于html的

第一个vue程序

  • {{}}是mustache的模板语法,mustache是jquery时代的模板引擎
  • {{}}中只能是表达式,不支持语句{{var test = 2}} ×
  • v-if和v-show的区别,v-if的判断条件不满足的dom不会渲染,v-show的判断条件不满足的dom会渲染(已经挂载到dom节点上了),但是不显示
  • v-bind 简写 :

组件基础及组件注册

  • 页面可以抽象为组件树
  • 用Vue.component去注册组件的时候需要保证第一个参数name是全局唯一的

目录

事件

  • v-on 简写 @
  • 阻止事件冒泡
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>

目录

插槽

  • 插槽的作用:分发内容(传递复杂内容的一种方式,因为没有办法通过简单地属性去传递复杂的内容,才设计了一个这样的API去传递复杂的内容)
  • 默认插槽:
  • 具名插槽:
  • 作用域插槽:本质上传递的是一个返回组件的函数

目录

单文件组件

使用Vue.component方式构建组建的缺点

  • 全局定义 (Global definitions) 强制要求每个 component 中的命名不得重复
  • 字符串模板 (String templates) 缺乏语法高亮,在 HTML 有多行的时候,需要用到丑陋的 \
  • 不支持 CSS (No CSS support) 意味着当 HTML 和 JavaScript 组件化时,CSS 明显被遗漏
  • 没有构建步骤 (No build step) 限制只能使用 HTML 和 ES5 JavaScript,而不能使用预处理器,如 Pug (formerly Jade) 和 Babel

目录

双向绑定和单向数据流不冲突

  • v-model只是语法糖,是简写的形式,本质上还是单向数据流,只是帮助我们简化了代码。对于Input标签,v-model是value属性和input事件的简写
<!--简写-->
<input v-model="message">{{message}}
<!--非简写-->
<input :value="message" @input="handleChange">{{message}}

handleChange(e) {
    this.message = e.target.message
}

v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:

  • text 和 textarea 元素使用 value property 和 input 事件;
  • checkbox 和 radio 使用 checked property 和 change 事件;
  • select 字段将 value 作为 prop 并将 change 作为事件。

自定义组件的v-model

Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  • 自定义组件想要多个属性的双向绑定,使用.sync修饰符
<!--简写-->
<text-document v-bind:title.sync="doc.title"></text-document>
<!--非简写-->
<text-document
  v-bind:title="doc.title"
  v-on:update:title="doc.title = $event"
></text-document>
<!--在事件中-->
handleChange(e) {
    this.$emit("update:title", ... )
    this.message = e.target.message
}
  • 总结:vue的双向绑定本质上还是单向数据流,v-model仅仅只是一种简写形式,它的目的只是让我们写更少的代码完成同样的功能。

目录

理解虚拟DOM及key属性的作用

  • jquery绑定事件,然后通过事件操作DOM
  • 不同的事件操作不同的DOM或者相同的DOM,变得越来越乱,所以造就了vue和react的诞生
  • vue和react都是通过引入数据中间层直接操作DOM,在VUE中不再关注DOM元素,仅仅关注数据state,所有的事件操作的对象都是数据state,然后通过VUE底层将数据映射到DOM。
  • 数据的变化会导致DOM的更新,DOM的更新也是非常耗性能的影响用户体验的,当数据变化后,如何尽可能的减少DOM的更新?
  • 于是出现了虚拟DOM
  • DOM树:由数据state和模板template构成、监测对象保存的树形结构的信息。
  • 两个DOM树的比对:正常比例算法O(n3),如果只对同层级的进行比较,就可以降低时间复杂度到O(n)
  • DOM动作:移动、新建、删除
  • 有Key就可以将一些删除新建的动作简化成移动
  • 有key也会影响到插入场景,可以减少DOM操作
  • 使用index作为key在list会动态新增删除的时候会出问题
  • vue和react的比对不一样,一个是单边比对,一个是双边比对

目录

如何触发组件的更新

没有特殊情况不要操作DOM

数据来源(单向的)

  • 来自父元素的属性
  • 来自组件自身的状态data
  • 来自状态管理器,如vuex,Vue.observable

状态data vs 属性props

  • 状态是组件自身的数据
  • 属性是来自父组件的数据
  • 状态的改变未必会触发更新
  • 属性的改变未必会触发更新

响应式更新

  • vue在实例化的时候会对data下的数据做一个getter、setter的转化,其实就是数据代理层
  • 在页面渲染render的时候,如果data中的数据被使用,就会放到watcher中去,下次更新的时候setter就会通知watcher,才去更新,没有被使用就不会到watcher中去,也就不会触发更新,这就是data或者prop变化,而组件没有更新的原因

目录

合理应用计算属性和侦听器

计算属性computed

  • 减少模板中的计算逻辑
  • 数据缓存
  • 依赖固定的数据类型(响应式数据)

computed是当数据变化才会执行方法,methods是当模板刷新就会执行方法


侦听器watch

  • 更加灵活、通用的api
  • watch中可以执行任何逻辑,如函数节流,Ajax异步获取数据,甚至操作DOM

多层级的嵌套监听就会用"b.c"这种方式,就可以独立监听b里面c的变化

深度监听:就是会对e下面所有属性进行监听

e: {
    handler: function(val, oldVal) {
        ...
    },
    deep: true
}

侦听器watch

  • computed能做的,watch都能做,反之则不行
  • 能用computed的尽量用computed

目录

生命周期的应用场景和函数式组件

生命周期

创建阶段

在这里插入图片描述

  • 在beforeCreate之前会执行事件的初始化包括生命周期的初始化
  • 在beforeCreate之后会对数据做响应式化处理,还有属性和侦听器的配置等
  • 然后执行created这个生命周期
  • 在created之后到了模板编译的阶段,再模板编译到render这个阶段(如果直接写的render函数,这个阶段会被跳过。一般我们写template,就是模板到编译到render,这些对于我们是透明的)
  • 接着是beforeMount,然后是render,render会给我们生成虚拟DOM,然后会去挂载真实DOM,挂载完之后执行Mounted
  • 在Mounted中会执行异步请求、操作DOM还有定时器等,但是在mounted之后vue不承诺我们子组件的DOM也会真正的挂载到我们的真实DOM上,这时我们需要this.$nextTick去把操作DOM的事情放在回调中

更新阶段

在这里插入图片描述

  • 被多次执行,数据变化时或强制更新(this.forceUpdate)时,就会去执行beforeUpdate
  • 在beforeUpdate中会去移除已经添加的事件监听器,一般开发中并不会用到事件监听器,因为vue本身提供的事件绑定监听机制已经足够我们使用了(但是如果是开发组件库,有可能会用到)
  • 接着执行render,生成最新的虚拟DOM,再之后更新真实DOM,完成之后调用updated
  • updated和mounted一样不承诺子组件的DOM更新完操作DOM的话,也需要放在this.$nextTick回调中,这时候需要添加一些事件监听器
  • 在beforeUpdate和updated中万万不可更改依赖数据,如果更改了,就会导致死循环,一更改就会执行更新阶段…直到浏览器爆掉

销毁阶段

在这里插入图片描述

  • beforeDestroy是销毁之前执行的,会去移除已经添加的事件监听器,还有计时器(不销毁可能会导致内存泄漏)等
  • destroy很少用

函数式组件

  • functional: true
  • 无状态、无实例、没有this上下文、无生命周期

一般用于展示

用函数式组件在模板中做临时变量(vue没有提供临时变量的功能,但是临时变量是很有必要的,不然在模板中会出现多次重复的逻辑计算,当然计算属性在很大程度上帮我们避免了这件事,但是计算属性依赖的数据必须是响应式数据)

<!--TempVar.js-->
export default {
    functional: true,
    render: (h, ctx) => {
        return ctx.scopedSlots.default && ctx.scopedSlots.default(ctx.props || {});
    }
}

<!--index.vue-->
<TempVar
    :var1="`hello ${name}`"
    :var2="destroyClock ? 'hello vue' : 'hello world'"
>
    <template v-slot="{var1, var2}">
        {{var1}}
        {{var2}}
    </template>
</TempVar>

目录

指令的本质

vue内置的指令(语法糖、标志位)

  1. v-text
  2. v-html
  3. v-show
  4. v-if
  5. v-else
  6. v-else-if
  7. v-for
  8. v-on
  9. v-bind
  10. v-model
  11. v-slot
  12. v-pre
  13. v-cloak
  14. v-once

v-text

  • v-text会把子元素下的所有内容替换掉,插入字符串
<div v-text="'hello vue'">hello world</div>
<!--hello vue-->

v-html

  • v-html会把子元素下的所有内容替换掉,插入标签,不建议使用,xss潜在风险存在
<div v-html="'<span style=&quot;color: red&quot;>hello vue</span>'">hello world</div>
<!--hello vue-->

v-show

  • v-show是否显示(隐藏)
<div v-show="'hello vue'">hello vue</div>
<button @click="show != show">change show</button>

v-if

  • v-if是否显示(直接删掉DOM)

v-else

  • 不能单独使用,必须和v-if配合使用

v-else-if

  • 不能单独使用,必须和v-if配合使用
<div v-if="number === 1">hello vue {{number}}</div>
<div v-else-if="number === 2">hello world {{number}}</div>
<div v-else="number === 1">hello geektime {{number}}</div>

v-for

  • for循环数组

v-bind

  • 简写 :key
<div v-for="num in [1,2,3]" v-bind:key="num">hello vue {{num}}</div>

v-on

  • 事件,简写 @click
<div v-on:click="number=number+1">number++</div>

v-model

  • 双向绑定语法糖指令

v-slot

v-pre

  • 绕过{{}}编译过程直接输出字符串,不常用
<div v-pre>{{this will not be compiled}}</div>

v-cloak

  • 使用频率最低,在单文件模式中没有任何作用,在html中直接写木板的时候才会用到

v-once

  • 这里绑定的变量number只会计算一次,后面不管如何变化都不会重新去渲染,对于性能优化很有帮助,但是很少用
<div v-once>{{number}}</div>

  • 指令其实就是语法糖,或者说标志位,模板编译到render函数的时候,会把指令编译成js代码
  • 这也是为什么Jsx和render函数并不支持内置指令的原因,因为指令确实帮我们简化了很多的代码量,jsx也在慢慢的支持内置指令,jsx也是语法糖,最终也会通过编译输出真正的render函数

自定义指令

  • 不是刚需,也可以通过其他方式实现

生命周期钩子(一个指令定义对象可以提供如下几个钩子函数)

  1. bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
  2. inserted: 被绑定元素插入父节点时调用
  3. update: 所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。
  4. componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
  5. unbind:只调用一次,指令与元素解绑时调用。
  • 进去的时候执行bind->inserted
  • 组件的VNode更新,update->componentUpdated
  • 组件销毁unbind
  • 组件重新绑定bind->inserted

目录

常用高级特性provide/inject

  • 平时开发不常用
  • 但在开发底层通用组件的时候,使用频率会相当高

组件通信
在这里插入图片描述

  • I节点和E节点如果要通信,属性prop和事件emit都需要层层传递冒泡,这样成本很高,也没有健壮性,provide和inject就是为了解决这个问题
  • A节点通过provide提供数据
  • E节点通过inject注入数据,通过层层冒泡的方式去A节点取数据
  • 实现A和E之间的通信
<!--A组件-->
<!--provide() {-->
<!--    return {-->
<!--        theme: {-->
<!--            color: this.color这里的color是字符串,不是响应式数据,它改变不会同步到子组件变化-->
<!--        }-->
<!--    }-->
<!--}-->
provide() {
    return {
        theme: this
    }
}
<!--this下面会挂载到data props method 等属性都可以取得到,因为data props是响应式的-->
<!--E组件-->
<h3 :style="{color: theme.color}">E</h3>
inject: {
    theme: {
        default: () => ({})
    }
}
<!--F组件-->
<h3 :style="{color: theme.color}">F</h3>
inject: {
    theme1: {
        from: "theme"
        default: () => ({})
    }
}
<!--vue很多东西都挂载到this上,可能注入的theme和本身的theme有冲突,可以通过from取别名-->
<!--I组件(函数式组件)-->
<template functional>
<h3 :style="{color: injections.theme.color}">I</h3>
</template>
inject: {
    theme: {
        default: () => ({})
    }
}
<!--C组件-->
provide() {
    return {
        theme: {
            color: "green"
        }
    }
}
<!--如果C组件也提供了一个theme,EF节点向上找颜色的时候,发现了C节点的数据,就不会再向上去找了,类似冒泡机制-->

目录

如何优雅地获取跨层级组件实例(拒绝递归)

ref引用信息

<p ref="p">hello</p>
<!--vm.$ref.p拿到这个DOM-->
<child-component ref="child"></child-component>
<!--vm.$ref.child拿到这个子组件实例-->
  • 如果要跨层级去拿组件实例,才用递归查找的话:代码繁琐、性能低效
  • react的ref是一个callback回调的形式,针对这个设计了:
    • 主动通知(setXxxRef)
    • 主动获取(getXxxRef)
<!--A节点-->
provide() {
    return {
        setChildrenRef: (name,ref) => {
            this[name] = ref;
        },
        getChildrenRef: name => {
            return this[name];
        },
        getRef: () => {
            return this;
        }
    }
}
<!--D节点-->
<ChildrenH v-ant-ref="c => setChildrenRef('childrenH', c)" />
// v-ant-ref是自己开发的,是回调的形式,每次节点更新的时候都会告诉上层节点已更新
// vue 1.0有v-ref的指令,且作用和v-ant-vue完全不同,所以暂且不使用v-ref,防止冲突
inject: { // 注入
    setChildrenRef: {
        default: () => {}
    }
}

目录

template和JSX的对比以及它们的性质

  • JSX和react有很大的联系,JSX是伴随着react产生的,但是又是独立的个体
  • 通过插件的形式,在vue中也可以使用JSX

template

  • 模板语法(HTML的扩展)
  • 数据绑定使用Mustache语法(双大括号)
<span>Message:{{msg}}</span>

JSX

  • javascript的语法扩展(JSX不是模板语法)
  • 数据绑定使用单引号
<span>Message:{this.msg}</span>

template VS JSX

  • 在JSX中可以写JS的各种逻辑,所以相对于template更加灵活
  • template是vue的特点和优点
  • template的优点:
    • 学习成本低
    • 大量内置指令简化开发
    • 组件作用域CSS
  • template的缺点:
    • 灵活性低
  • JSX的优点:
    • 灵活
  • 组件分为两类:偏视图表现和偏逻辑的,表现类的组件远多于逻辑类组件
  • 推荐前者使用模板,后者使用JSX或渲染函数
  • template和JSX都是语法糖
<!--JSX-->
export default {
    props: {
        level: {
            type: Number,
            default: 1
        }
    },
    <!--JSX-->
    render: function(h) {
        const Tag = `h${this.level}`;
        return <Tag>{this.$slots.default}</Tag>
    },
    <!--JS-->
    render: function(createElement) {
        return createElement(
            "h" + this.level, // 标签名称
            this.$slots.default // 子元素数组
        )
        <!--复杂的时候,像这样层层嵌套去写,复杂度就比较高了-->
    }
}

目录

生态篇

为什么需要VueX

Vuex是一种状态管理模式

在这里插入图片描述

目录

为什么需要VueX

目录

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值