一、Vue中深度作用选择器,有作用域的 CSS

规则一: 使用 scoped 后,父组件的样式将不会渗透到子组件中。不过一个子组件的根节点会同时受其父组件有作用域的 CSS 和子组件有作用域的 CSS 的影响。这样设计是为了让父组件可以从布局的角度出发,调整其子组件根元素的样式。
  • 引出场景一:在组件中用了第三方组件,但是第三方组件class样式需要我们重新定制,比如我们引入了ElementUI组件库,我们需要对使用的组件中存在的class="el-form-item__label"样式进行修改,这时我们直接对el-form-item__label进行样式修改是不行的。
  • 解决方案1:image.png
  • 解决方案2:有些像 Sass 之类的预处理器无法正确解析 >>>。这种情况下你可以使用 ::v-deep 操作符取而代之——这是一个 >>> 的别名,同样可以正常工作。
  • 场景一的应用:image.png
  • 场景一的原理:实际就是对el-form-item__label样式加上了[data-v-30be3d08]属性,这个属性和scoped生成的属性一致,这样才做到深度作用。image.png

二、Vue.extend()

创建Vue构造函数模型,结合参数是一个包含组件选项的对象,去创造一个个子类实例。在我们做一个Modal的时候有用,配合自定义指令,可以生产定制化高复用组件。
Vue.component是直接创建一个个组件实例。
  • image.png

三、作用域插槽

  • 场景困扰:组件模板中我们可以拿到一个数据,但是组件应用于父组件中后再想访问数据就会变得困难,除非洞穿或者传值或者vuex解决,但是作用域插槽给了我们一个解决方案

四、Element-UI table中el-table-column 标签下的 input 标签无法输入问题

  • 如下情况的写法是无法对输入框进行输入的。原因是:在table表单中,el-table已经绑定了:data值,所以所有的双向绑定都需要是:data上的值。

    • image.png
  • 像这样是比较好的解决方案

    • image.png

五、For运行机制及熟练map、filter、reduce方法

  • 看下面两个例子

    • 正确:image.png
    • 错误:image.png
  • 总结:arr.splice执行后,arr的长度自动变短了,i的值是根据arr长度程序去选择当前长度中对应的下标i,我在错误的例子中j--只会减短循环的次数,并无法做到index和arr变短后下标的对应,其实只有i--才是正确的,保证了arr的长度变短的同时i保持一致。但我对for的循环机制理解是没有错误的。

六、上一个点的延伸更加吊鬼的地方

  • 错误,程序死亡,原因是由于作用域的问题,arr.length长度在变,你以为赋值给j,j的长度也会变,其实不是的,j的长度永远等于第一次定值的时候的长度,i永远在遇到第一个undefined时--,永远在i=1这个位置跳不出来了:image.png
  • 正确:image.png

七、 Vue2中无法探测普通的新增 property,必须做Vue.set()深入响应。

  • Object.defineProperty的限制:

    • Vue 无法检测 property 的添加或移除。
    • image.png

-遇到如下两个场景,一种可以实现响应式,一种却不能。

  • 可以实现:我们在异步获取到数据后,对数据进行forEach遍历,并往这个res中加字段赋值,然后再通过 this.[目标data对象] = res,这样是可以实现响应式的。

    • 如图:image.png
  • 不可以实现:我们在获取到数据res后,还需要拿着res再做更多的异步处理才能往里添加字段,同样直接用上面的方式,是不可以实现。原因是内部机制,res再异步后添加的字段并没有被做响应式,因为eventLoop机制的原因,在同步代码this.[目标data对象] = res中已经完成了第一次赋值,后面异步promise拿到的数据再往this.[目标data对象] 中加字段就出现了上面Object.defineProperty的限制第一条。我们只能通过Vue.set()深入响应式的方法来解决。

    • 如图:image.png

八、 浮动清除

什么是浮动:

image.png
解决方法:在浮动元素后面的一个空div中clear:both

九、 git log --graph图解析

image.png

  • 像这样的图怎么去看,当前最内侧的一条线代表的是develop主支。解析:当wiki commit版本67042...时,这张图才看起来清楚了,※号点回到了develop主支上,其实是因为这个图是一个历史git log提交线图,是一个可视逻辑处理后的图。它表示,在wiki commit版本67042...之前包含了e07433...,4cd034...,2169f2b...,603e34c...这四个commit版本,你可以回退任意一个commit版本。此图显示的时候wiki commit版本67042...有2个parent,一个是e07433...,一个是2169f2b...。
  • 但我们如果强行回退到4cd034...,这张log图会重新绘制逻辑变化,这时最内侧为当前develop,但他的parent就不会是这样了,是逻辑重新判断后的,图中看到的4cd034...版本parent出现在了最内侧develop主支上,另一个parent是此图主支中的603e34c...。

    • 切换后的分支是这样看的,其实是可以根据graph图溯源的,很方便!!:image.png
      -这个是我开发时的情形,我们看一个简单的例子。

image.png
image.png

git的粗略机制:

git使用起来我们只关心分支线。但其实git还有当前版本和提交版本时的“时间线”,并且会给这个版本线冠以开发者标签标记,方便git算法比较。
所以merge的时候,不仅仅对“别人”会做上标记,还会对历史commit比较,再做出是否冲突的判断。比如说同事和我同时维护一个仓库,我们都在7月1日保持了同步commit1,但是7月2日同事对a.vue,b.vue,c.vue做了修改,7月2日我对c.vue,d.vue做了修改。7月2日下班前,同事比我早提交了他的commit2,这时我push代码会出现问题,需要先pull(fetch+merge)同事的commit2,fetch下来的代码会和我的代码做比较,但是由于我没有对a.vue,b.vue文件做修改,git只会对c.vue文件(因为我们都有修改,有可能出现冲突)做出冲突判断。对于a.vue,b.vue文件git已经在同事那侧做好了commit1和commit2的merge(或者说commit1到commit2的提交比较),到我这里pull的时候也就是copy了一下(commit1和commit2的merge)这个逻辑判断,并不再需要进行再比较。

十、 delete删除数组元素的坑

delete删除数组元素,它是将内容删除为空,但是元素的个数不变
  • [ 1, undefined, undefined ]
  • 遍历后使用delete: [ <1 empty item>, undefined, undefined ]
  • 解决方案考虑使用filter, 直接return就会自动删除数组中的undefined。

十一、 css中的 ~ 和 >

css中“>”是:

css3特有的选择器,A>B 表示选择A元素的所有子B元素。
扩展:

  • .a,.b{逗号指相同的css样式}
  • .a .b{空格指后代元素}后代元素:儿子,孙子,重孙子等等都包括在内的元素
  • .a>.b{大于号指子代元素}子元素:儿子
css中“~”是:
p~ul{
  background:#ff0000;

}

 <p>快乐生活</p>

<ul>
  <li>生活</li>

  <li>生活</li>

  <li>生活</li>

</ul>

定义和用法:

  • p~ul选择器 p 之后出现的所有 ul
  • 两种元素必须拥有相同的父元素,但是 ul 不必直接紧随 p

十二、 ElementUI的table表单中header-row-class-name等之类的table属性

header-row-class-name使用例子

注释:header-row-class-name是表头行的 className 的回调方法,也可以使用字符串为所有表头行设置一个固定的 className。(表头行指的是table中最上面的那row)

使用:

  • 需求是要把table中的selection列的选择按钮对齐。思路有两种,一种就是用header-row-class-name改变表头行的样式来改变,另一种就是对内容行的样式洞穿并利用标签选择器,只对内容行的选择div进行样式变动。
  • image.png
  • image.png
  • scss
    image.png

十三、 CSS3 : nth-child() 选择器

image.png

同上一题的题目:如果我们需要对内容行的第四个子元素进行布局设置,首先可以利用row-class-name是指内容行className,然后定位到它的td第四个子标签,做内容布局

  • image.png

十四、 正则输入判断,利用input上的onkeyup快速限制用户输入

过滤非数字
onkeyup="value=value.replace(/[^\d]/g,'')"
过滤非数字和 .
onkeyup="value=value.replace(/[^\d.]/g,'')"

十五、 template中的插槽

  • Vue具名插槽: 就是子组件提供给父组件使用的一个占位符,父组件中的具名插槽将匹配子组件内容片段中有对应 slot 特性的元素。用<slot> </slot>表示,父组件可以在这个占位符中填充任何模板代码,如 HTML、组件等,填充的内容会替换子组件的<slot> </slot>标签。6以后的版本中的用法是这样的:<template v-slot:header> 在父组件中使用模板语法,使用v-slot绑定插槽的名字。<slot name="header"></slot> 在子组件中仍然使用name来作为插槽的标识符。
  • Vue作用域插槽: 有时让插槽内容能够访问子组件中才有的数据是很有用的,但是因为只有子组件可以访问到例如user数据,而我们提供的内容是在父级渲染的。为了让user数据在父级的插槽内容中可用,第一步:在子组件中我们可以将user作为 <slot> 元素的一个 attribute 绑定上去,<slot v-bind:user="user"> {{ user.lastName }} </slot>,第二步:绑定在 <slot> 元素上的 attribute 被称为插槽 prop。现在在父级作用域中,我们可以使用带值的 v-slot 来定义我们提供的插槽 prop 的名字。<template v-slot:default="slotProps"> {{ slotProps.user.firstName }} </template>,在这个例子中,我们选择将包含所有插槽 prop 的对象命名为 slotProps,但你也可以使用任意你喜欢的名字。

十六、 ElementUI中的 <template slot-scope="scope"> 原理剖析

ElementUI中的el-table组件
  • 我们在使用el-table表的时候,el-table双向绑定了一个数组list,它的下一级组件使用是el-table-column组件,这样是官方的例子。然后在el-table-column组件上会prop进行双向绑定,绑定的对象是list数组中元素的一个属性字段,但是我们发现这种绑定方式并不灵活。我们可能需要对list数组中的每个元素,即每个row进行操作,其实elment-ui封装好的el-table-column组件里面有这个row。
  • 结合上面Vue作用域插槽的概念:让当前父组件能够访问子组件才有的数据。row在elment-ui封装好的el-table-column子组件中就是<slot v-bind:row="row"></slot>。我们用作用域插槽的方法就是为了让当前父组件中能够访问到el-table-column子组件中的row。

在我们写业务逻辑的组件中就是这么用:

<el-table-column>
  <template v-slot:default="slotProps">
    {{ slotProps.row.xxxx属性 }}
  </template>
</el-table-column>

十七、 vscode注释@param快速实现

vscode 已经内部集成了,你在函数的上一行输入 /** 然后enter就可以了

十八、 Vue源码中的深拷贝源码,非常优雅

  function deepCopy(obj,cache = []){
      // 如果为普通数据类型,则直接返回,完成拷贝
      if (obj===null || typeof obj !== "object"){
          return obj
      }
        // cache用来储存原始值和对应拷贝数据,在递归调用deepCopy函数时,如果本次拷贝的原始值在之前已经拷贝了,则直接返回储存中的copy值,这样的话就不用再循环复制本次原始值里面的每一项了。
        // 还有一个更为重要的作用,假如原始值里面嵌套两个引用地址相同的对象,使用cache可以保证拷贝出来的copy值里面两个对象的引用地址也相同。
        // 如果find查找的是一个空数组,则不会执行
      const hit = find(cache,c=>c.original===obj)
      if(hit){
          return hit.copy
      }
      // 定义拷贝的数据类型
      const copy = Array.isArray(obj) ? [] : {}
      // 用来记录拷贝的原始值和copy值
      cache.push[{
          original:obj,
          copy
      }]
      // 递归调用深拷贝函数,拷贝对象中的每一个值
      Object.keys(obj).forEach(key=>{
          copy[key]=deepCopy(obj[key],cache)
      })
      return copy
    }

十九、原生 JavaScript 解析字符串模板为 DOM 对象的能力?

创建一个 template 模板元素,放入的 HTML 字符串会被自动解析成 DocumentFragment ,可以直接插入到页面中。

function parseToDOM(htmlstring) {
  const tpl = document.createElement('template');
  tpl.innerHTML = htmlstring;
  return tpl.content;
}

const el = parseToDOM('<h1>233</h1>');
document.body.append(el);

不过需要注意 <template> 的兼容性,IE 用不了。

二十、 内置的组件之一的component组件<component></component>

image.png

二十一、 单向绑定v-bind中的.prop.sync修饰符

image.png

关于.prop

区分DOM propertyHTML attribute,这是angular文档中的一个解释。
他们的临界点就是在一旦浏览器解析了HTML元素,就会创建这个DOM对象。
image.png
image.png

关于.sync

是一个语法糖,它会扩展成一个更新父组件中绑定值的 v-on 侦听器。

  • 本来v-on:update:title="doc.title = $event" 中的doc.title = $event是一个函数表达式
  • 用了.sync语法糖后,v-bind:title.sync="doc.title"中的:title.sync的title是子组件中的一个props,doc.title是父组件data函数里doc对象中的一个属性,实现一个简写方法,子组件不再需要$emit触发事件来传值给监听器。
    image.png

二十二、 关于回调和异步的问题

回调和异步是两个概念,异步和回调没有关系。

  • 同步的也有很多用回调的
  • 回调只是异步传输结果的一个方式
回调分成同步回调和异步回调。
  • 基本上我们如果把简单的一个同步函数作为参数传递给一个主函数调用的时候,基本上这种回调就是同步回调。
  • 但之所以回调还有异步回调的原因是因为回调被包在了异步函数中。但是其实从JavaScript层面是没办法「手工」地实现一个异步函数的,必须直接或间接地使用语言提供的异步函数(setTimeout)或宿主提供的异步函数(如 Node.js 的 fs.readFIle, 或浏览器的 XHR),这两类异步函数是没办法用 JavaScript 描述的,它们都是由本地代码(如 C++)直接和引擎(V8)交互才能做到的。当然js发展到现在,通过Promise.resolve也能实现一个异步函数。

二十三、 Vue.js 和 Vue.runtime.js

Vue有两个版本:
  • 完整版:vue.js、vue.min.js(运行时版+编译器)(编译器:将模板字符串编译成为JS渲染函数的代码)
  • 运行时版:vue.runtime.js、vue.runtime.min.js(用来创建 Vue 实例、渲染并处理虚拟 DOM 等的代码)

1、vue-cli 创建的 vue 项目,默认的配置是 vue.runtime.js 版本
2、后缀为.min.js的是生产版

image.png


Macrohoo
28 声望2 粉丝

half is wisdom!🤔