• 猿创征文 |《深入浅出Vue.js》打卡Day7


    第15章 指令的奥秘

    指令Vue.js提供的带有v-前缀的特殊特性,用于辅助开发者渲染页面的基本结构。

    15.1 指令原理概述

    指令相关的知识贯穿Vue.js内部各个核心技术点。在模板解析阶段,我们在将指令解析到ASTdirectives属性中,然后使用AST生成代码字符串的过程中实现某些内置指令的功能,最后在虚拟DOM渲染的过程中触发自定义指令的钩子函数使指令生效。
    在这里插入图片描述

    15.2 指令的分类

    15.2.1 内容渲染指令

    • v-text 几乎不用
     <p v-text="age">年龄</p>// 会覆盖元素内部原有的内容
    
    • 1
    • {{}} 插值表达式(Mustache) 实际开发中用的最多 支持JS语句
    <!-- {{}} 只是内容的占位符,不会覆盖原有的内容 -->
            <p>年龄:{{age}}</p>
    
    • 1
    • 2
    • v-html 可以把包含HTML标签的字符串渲染到页面
     <p v-html="info"></p>
     
     info: "

    个人信息

    "
    ,
    • 1
    • 2
    • 3

    15.2.2 属性绑定指令

    • v-bind 给元素属性动态绑定值,简写英文 :
     姓名: <input type="text" v-bind:placeholder="tips">
     
      tips: '请输入名称',
    
    • 1
    • 2
    • 3

    补充 :在使用v-bind属性绑定期间,如果绑定内容需要进行动态拼接,则字符串的外面应该包裹单引号,支持JS运算,例如:

    <div :title=" 'box' + index ">这是一个div</div>
    
    • 1

    15.2.3 事件绑定指令

    • v-on 事件绑定,简写为@
     <button v-on:click="add(2)">+1</button>
     
     methods: {
                    // add:function(){} 简写如下
                    add(n) {
                        this.count += n; // this就是vm实例,它里面有个count值
                    },
                    reduce() {
                        this.count -= 1;
                    }
                }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    15.2.4 双向绑定指令

    • v-model 事件修饰符
    <--.number 自动将用户的输入的内容进行处理,转换为数字格式
              .trim 自动过滤用户输入的首尾空白字符
              .lazy 在失去焦点的时候更新-->
    
            <input type="text" v-model.number="n1">+<input type="text" v-model.number="n2">={{n1+n2}}
            <hr>
            <input type="text" v-model.trim="username">
            <button @click="showbtn">点击获取名字</button>
            <hr>
            <input type="text" v-model.lazy="username">
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    15.2.5 条件渲染指令

    • v-if / v-show 按需控制DOM的显示与隐藏
      <!-- v-if 是动态创建和动态移除来实现的   一般这个用的多-->
            <!-- 如果刚进入页面的时候,某些元素不需要被展示,而且后期这个元素很可能不需要被展示,v-if性能会更好 -->
            <p v-if="flag">这是被v-if所控制的元素</p>
    
            <!-- v-show 是动态添加或移除style="display:none"样式来实现元素显示与隐藏 -->
            <!-- 如果要频繁的切换元素的显示状态,用v-show性能最好的 -->
            <p v-show="flag">这是被v-show所控制的元素</p>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • v-if v-else-if v-else
    		<div v-if="type=='A'">优秀</div>
            <div v-else-if="type=='B'">良好</div>
            <div v-else-if="type=='C'">一般</div>
            <div v-else="type=='D'">较差</div>
    
    • 1
    • 2
    • 3
    • 4

    15.2.6 列表渲染指令

    • v-for 基于一个数组来循环渲染一个列表结构
    <tbody>
    // index 是索引 
    // list是data中的列表
    // v-for 指令,一定要绑定一个:key属性,尽量把id作为key的值 
    // key值不能重复,否则会在终端报错
    // 官方对key的值类型,是有要求的:字符串或者数字类型
        <tr v-for="(item ,index)in list" :key="item.id" :title="item.name">
        <td>{{index}}</td>
        <td>{{item.id}}</td>
        <td>{{ item.name })</td>
        </tr>
    </tbody>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    第16章 过滤器的奥秘

    Vue.js 运行我们自定义过滤器来格式化文本。它可以用在两个地方:双花括号插值v-bind表达式。它应该被添加在JavaScript表达式的尾部,由“管道”符号指示:

    // 在双花括号中
    {{message | capitalize}}
    
    // 在v-bind中
    <div v-bind:id="rawId | formatId"></div>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    此外,过滤器可以串联,比如:

    {{message | filterA | filterB}}
    
    • 1

    在这个例子中,fillterA被定义为接收单个参数的过滤器函数,表达式message的值多为参数传入到fillterA过滤器函数中。然后将过滤函数fillterA的执行结果当作参数传递给fillterB函数。

    过滤器还可以接收参数,比如:

    {{message | filterA('arg1','arg2')}}
    
    • 1

    在这个例子中,filterA被定义为接收三个参数的过滤器函数。其中message的值作为第一个参数,普通字符串‘arg1’作为第二个参数,表达式’arg2’的值作为第三个参数

    16.1 过滤器原理概述

    {{message | capitalize}}
    这个过滤器在模板编译阶段会编译成下面的样子:
    _s(_f("capitalize")(message))
    
    • 1
    • 2
    • 3

    这个代码原理简单的来说,其实就是执行了capitalize过滤器函数并把message当作参数传递过去,接着将capitalize过滤器处理后的结果当作参数传递给toString函数。最终toString函数执行后的结果会保存到VNode中的text属性,去渲染视图。

    其中_s函数是toString函数的别名,_f函数是resolveFilter的别名,其作用是从 this.$options.filters中找出注册的过滤器并返回。

    resolveFilter的内部原理

    _f函数是resolveFilter函数的别名。

    resolveFilter代码如下:
    在这里插入图片描述
    resolveAsset 查找过滤器代码如下:
    在这里插入图片描述
    在这里插入图片描述
    这里首先判断参数id 的类型(它是过滤器id ),它必须是字符串类型,如果不是,则使用return语句终止函数继续执行。随后声明变量assets并将options[type]保存到该变量中。事实上,resolveAsset函数除了可以查找过滤器外,还可以查找组件和指令。

    本例中变量assets中保存的是过滤器集合。
    1、通过hasOwn函数检查assets自身是否存在id属性,如果存在,则直接返回结果。hasOwn函数基于0bject.prototype.hasOwnProperty实现。
    2、如果不存在,则使用函数 camelizeid驼峰化之后再检查 assets 身上是否存在将id驼峰化之后的属性。
    3、如果驼峰化后的属性也不存在,那么使用capitalize函数将id的首字母大写后再次检查assets中是否存在。
    4、如果还是找不到,那么按照前面的顺序重新查找―遍属性,不同的是这次将检查原型链.'查找原型链很简单:只需要访问属性即可。如果找到,则返回过滤器。如果找不到,那么在非生产环境下在控制台打印警告。最后,无论是否找到,都返回查找结果。

    注册过滤器有两种途径:注册全局过滤器在组件的选项中定义本地的过滤器。全局注册的过滤器会保存在Vue构造函数中。
    resolveAsse函数在查找过滤器的过程中并没有去vue构造函数中搜索过滤器。这是因为在初始化Vue.js实例时,把全局过滤器与组件内注册的过滤器合并到this.$options.filters中了,而this.$options.filters其实同时保存了全局过滤器和组件内注册的过滤器。resolveAsset只需要从this.$options.filters中查找过滤器即可。

    16.2 解析过滤器

    parseFilters函数,专门用来解析过滤器,它可以将模板过滤器解析成过滤器函数调用表达式。逻辑就是,解析出过滤器的列表后,循环过滤器列表并拼接一个字符串即可。


    第17章 最佳实践

    17.1 为列表渲染设置属性key

    key这个特殊属性主要用在Vue.js的虚拟DOM算法中,在更新子节点时,需要从旧虚拟节点列表中查找与新虚拟节点相同的节点进行更新。如果这个查找过程设置了属性key,那么查找速度会快很多。所以无论何时,建议尽可能地在使用v-for时提供key。

    17.2 在 v-if / v-if-else / v-else 中使用key

    如果一组 v-if + v-else 的元素类型相同,最好使用属性key。默认情况下,Vue.js会尽可能高效地更新DOM。这意味着,当它在相同类型的元素之间切换时,会修补已存在的元素,而不是将旧的元素移除,然后再同一位置添加一个新元素。如果本不相同的元素被识别为相同,则会出现意料之外的副作用。如果添加了属性key,那么在对比虚拟DOM时,则会认为它们是两个不同的节点,于是会将旧元素移除并在相同的位置添加一个新元素,从而避免意料之外的副作用。

    17.3 路由切换组件不变

    在使用Vue.js开发项目时,最常遇到的一个典型问题就是,当页面切换到同一个路由但不同参数的地址时,组件的生命周期钩子并不会重新触发。
    这是意味vue-router会识别出两个路由使用的是同一个组件从而进行复用,并不会重新创建组件,因此组件的生命周期钩子自然也不会被触发。

    下面总结3个方法来解决这个问题:
    1、路由导航守卫beforeRouteUpdate
    组件的生命周期钩子虽然不会重新触发,但是路由提供的 beforeRouteUpdate守卫可以被触发。因此,只需要把每次切换路由时需要执行的逻辑放到 beforeRouteUpdate守卫中即可。这是比较推荐的一种方式。

    2、观察 $route 对象的变化
    通过watch可以监听到路由对象发生的变化,从而对路由变化作出响应。
    在这里插入图片描述
    这个方式也可以解决上述问题。但代价是组件内多了一个watch,这会带来依赖追踪的内存开销。如果最终选择使用watch解决这个问题,推荐只观察自己需要的query,这样有利于减少不必要的请求。

    3、为router-view组件添加属性key
    这中做法非常取巧,非常“暴力”,但非常有效。它本质上是利用虚拟DOM在渲染时通过key来对比两个节点是否相同的原理。通过给 router-view组件设置key,可以使每次切换路由时的key都不一样,让虚拟DOM认为router-view组件时一个新节点,从而先销毁组件,让后再重新创建新组件。即使是相同的组件,但是如果url变了,key就变了,Vue.js就会重新创建这个组件。所以组件内的生命周期会重复触发。

    优点:简单粗暴,改动小;
    缺点:每次切换路由组件时都会被销毁并且重新创建,非常浪费性能。

    17.4 区分Vuex与props的使用边界

    通常,在项目开发中,业务组件会使用Vuex维护状态,使用不同组件统一操作Vuex中的状态。这样不论是父子组件间的通信还是兄弟组件间的通信,都很容易。

    对于通用组件,我会使用props语句事件进行父子组件间的通信(通用组件不需要兄弟组件间的通信)。这样做是因为通用组件会拿到各个业务组件中使用,它要与业务解耦,所以需要使用props获取状态。

    17.5 避免 v-if 和 v-for 一起使用

    Vue.js处理指令时,v-forv-if具有更高的优先级。

    17.6 为组件样式设置作用域

    Css 的规则都是全局的,任何一个组件的样式规则都对整个页面有效。因此,我们很容易在一个组件中写了某个样式,而不小心影响了另一个组件的样式,或者自己的组件被第三方库的CSS影响了。

    解决方法:在Vue.js中,可以通过scoped特性或CSS Modules(一个基于class的类似BEM的策略)来设置组件式作用域。
    在这里插入图片描述
    在这里插入图片描述
    在组件库,我们应该更倾向于选用基于class的策略而不是scoped特性

    17.7 避免在scoped中使用元素选择器

    scoped样式中,类选择器比元素选择器更好,因此大量使用元素选择器是很慢的。

    17.8 避免隐性的父子组件通信

    我们应该优先通过prop和事件进行父子组件之间的通信,而不是使用this.$parent或改变prop

    17.9 单文件组件的文件名的大小写

    单文件组件的文件名应该始终是单词首字母大写,或者始终是横线连接的

    应用特定样式和约定的基础组件(也就是展示类的,无逻辑的或无状态的组件)应该全部以一个特定的前缀开头,比如BaseAppV
    在这里插入图片描述
    在这里插入图片描述
    只拥有单个活跃实例的组件以The前缀命名,以示其唯一性;
    在这里插入图片描述
    和父组件紧密耦合的子组件应该以父组件名作为前缀命名;

    组件名应该倾向于完整单词而不是缩写;

    在单文件组件和字符串模板中的组件名应该总是单词首字母大写,但是在DOM模板中总是横线连接的,JS中,单词首字母大写的是类和构造函数;

    多个特性的元素应该分多行撰写,每个特性一行。
    在这里插入图片描述

    《深入浅出Vue.js》已经阅读完成,这本书还是蛮不错的,如果有写的不好的地方,欢迎来讨论

    在这里插入图片描述

  • 相关阅读:
    AIE聚甲基丙烯酸甲酯PMMA微球/聚苯乙烯包覆聚AIE微球/AIE聚四苯基乙烯自由基溶液聚合微球研究
    情侣天气推送升级简单版 & windows定时自动推送教程
    关于 React Hook 可能出现的使用误区总结
    图像目标检测-带旋转的矩形预测框
    强化学习
    超强、超详细Redis入门教程
    使用 Helm3 部署 Loki
    Sentence-BERT+Milvus实现智能问答系统
    【Linux】浅谈进程等待
    SpringBoot整合MQTT
  • 原文地址:https://blog.csdn.net/qq_48701993/article/details/126827321