木瓜太香

木瓜太香 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 该用户太懒什么也没留下

个人动态

木瓜太香 发布了文章 · 10月18日

vue任意关系组件通信与跨组件监听状态 vue-communication

大家好!我是木瓜太香!

众所周知,组件式开发方式给我们带来了方便,不过也引入了新的问题,组件之间的数据就像被一道无形的墙隔开,如果我们希望临时让两个组件直接通信,vuex 太巨,而 $emit 又不好维护 provider 不可控 这个时候就该今天的主角 vue-communication 登场了!

vue-communication介绍

  • 他是一个可观测可调试的vue组件通信方案
  • 任意关系组件可直接通信
  • 支持跨组件监听数据变化
  • 支持发送离线数据

安装

yarn add vue-communication
// 或者 npm install vue-communication -D

引入

import { $sender, $receiver } "vue-communication";
Vue.prototype.$sender = $sender;
Vue.prototype.$receiver = $receiver;

视频教程

<iframe data-original="//player.bilibili.com/player.html?bvid=BV1sD4y1d7mD&page=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" style="min-height: 400px"> </iframe>

用法

基本概念:

该组件暴露两个主要 API 一个是发送者 $sender 一个是接受者 $receiver,所有的通信都通过这两个方法来实现,这里希望大家将 $sender 理解成发送意图的发送者,他发送的是意图,意图就是希望做一件什么事情。

意图类型: dataOncemodifyOncedatamodifywatch

目前只有以上5种意图分别涵盖了:发送数据的一次和多次,修改数据的一次和多次,跨组件监听数据变化

发送数据:

假如 A 组件只向 B 组件发送一次数据:

A 组件中直接使用 this.$sender("dataOnce-A-B",{d: "我是数据"})

B 组件中在任意时刻(哪怕B都还没挂载都行,放心食用)使用this.$receiver("dataOnce-A-B") 这个函数返回一个 Promise 对象,直接 .then 接收即可

发送多次就用 this.$sender("data-A-B","我是数据") ,该方法调用多次,对应组件就会多次接收该数据

接收会有变化,由于会多次接收所以无法使用 Promise 来实现,请在参数追加回调this.$receiver("data-A-B",function(data){ // data就是数据 })

注意:

这里面的 意图修饰符-组件1-组件2 的格式是强制的,不管你的组件名有多长,你都要完整的给出!下面的修改数据也一样,对应到 data-A-B 这个案例,其整个字符串可以称为一个“意图”,data 叫做意图修饰符。

接收回执:

我相信大家都明白一个道理,如果委托 A 给 B 送东西,在 A 送到之后不应该默不吭声的就完了,而是应该告诉你一声,嘿!你让我送的东西我已经送到了哦!这就是回执。

需要注意的是回执目前只有在一次性操作中才会有,例如 dataOncemodifyOnce

他们通过 $sender返回的 Promise 对象给出,让发送者可以知道,我发送的数据什么时候被接收了

this.$sender("dataOnce-A-B","木瓜太香")
.then(flag => {
    console.log("接受者已经接受到数据了!")
})

修改数据:

A 组件中使用 this.$sender("modifyOnce-A-B","name","木瓜太香") 表示 A 组件要修改 B 组件中的 name 属性把他变为 木瓜太香

B组件中使用 this.$receiver("modifyOnce-A-B","name") 即可完成修改,注意第二个参数必须传,这是一个许可,表示你认可 A 组件修改当前组件的 name 属性,如果你写错了或者没传那么许可不成立,这是一个让数据变动可预测也强迫开发者需要更清楚自己在做什么的一个实现。

如果你要改 obj 对象下的 name 那么可以写成 this.$sender("modifyOnce-A-B","obj.name","木瓜太香")

如果你要修改多次可以参照 data 意图的示例,使用 modify 意图修饰符即可,注意,目前修改是没有回调的,如果你想知道数据什么时候被修改,可以自己在组件内部监听。

跨组件监听数据:

假如 A 组件要监听 B 组件中的 name 数据变动:

A 组件使用 this.$sender("watch-A-B","person.name",function(nv,ov){ // nv 表示新值 ov 表示旧值 })

B 组件只需要给出一次许可即可: this.$receiver("watch-A-B","person.name")

我自己建了一个web前端的交流裙有兴趣的可以加入进来交流哦:245650187(免费)237871108(收费)。
个人微信: GD6570 个人球球:718879459 当然你也可以哔哩哔哩搜索木瓜太香
查看原文

赞 0 收藏 0 评论 0

木瓜太香 发布了文章 · 9月15日

vue父子组件状态同步的最佳方式续章(v-model篇)

大家好!我是木瓜太香!一名前端工程师,之前写过一篇《vue父子组件状态同步的最佳方式》,这篇文章描述了大多数情况下的父子组件同步的最佳方式,也是被开源中国官方推荐了,在这里表示感谢!

这次作为续章是对上一篇文章的特殊情况的补充,并会给出较详细的描述与代码演示,当然如果你单看这篇文章来解决特定问题也是可行的。

对于父子组件状态同步,这篇文章 《vue父子组件状态同步的最佳方式》 讲述了大多数情况下的最优解,但是当我们希望自己创建的可复用组件和封装的逻辑能够尽量行为一致的时候情况可能会有所不同,举个例子,我们现在要封装一个输入框组件叫做 MyInput 我们知道普通的输入框通常会使用 v-model 来做双向数据绑定,这里如果想让封装的 MyInput 组件在使用上与普通的输入框是一致的,我们就难免要让自定义组件也支持 v-model 指令,这之中其实本质上也会涉及到父子组件的状态同步问题,使用我们之前讲的方式也能基本实现,只是借助 vue 暴露出来的 api 可以让我们写法更优雅,接下来我们使用不同的方式来实现这个组件。

原来的实现方式

自定义的MyInput组件

<template>
  <div class="myInput">
      <!-- 这里只能用 vModel 不可以使用横杠写法 -->
    <input type="text" :value="vModel" @input="inputHandle">
  </div>
</template>

<script>
export default {
  name: "MyInput",
  props: {
      // 这里也可以写成 'v-model': String 但是建议根据风格来,如果左边都没有引号就直接驼峰
    vModel: String
  },
  methods: {
    inputHandle (event) {
        // 注意:这里使用 update:v-model 或 update:vModel 都可以
      this.$emit("update:v-model", event.target.value)
    }
  }

}
</script>

使用方式

// 方式一
<my-input :v-model="text" @update:v-model="text = $event"></my-input>
// 方式二
<my-input :v-model.sync="text"></my-input>

可以看到,原来的方式也能实现,但是就使用来说v-model被当成属性,一定要在前面加上:才可以用动态属性,结果就变成了:v-model,然后我们为了简化写法去掉事件绑定,我们最终的效果就是 :v-model.sync这种写法总会让人觉得怪怪的,接下来我们就来解决这个问题

vue-api的方式实现

自定义的MyInput组件

<template>
  <div class="myInput">
    <input type="text" :value="value" @input="inputHandle">
  </div>
</template>

<script>
export default {
  name: "MyInput",
  props: {
    value: String
  },
  methods: {
    inputHandle (event) {
      this.$emit("input", event.target.value)
    }
  }

}
</script>

使用方式

<my-input v-model="text"></my-input>

看到这里可能一部分同学会一脸懵逼,这就同步了?emm,其实还真同步了,那 value 从哪儿来的,input 事件也没绑定啊,的确这些都被我们省略掉了,其实这是 vue 的 api 带给我们的便利,在我们试图向自定义组件传入 v-model 这个特殊的属性的时候,vue 会帮我们做两件事,一件是将 v-model 中的值作为 value 的值向下传递,这是我们在内部要写 props value 的原因,另一件是在当前自定义组件上监听 input 事件,并在触发改事件的时候,将第一个参数赋值给 v-model 中的变量。你可以看到在我们肉眼不可见的地方 vue 为我们做了很多实际,但是大家要明白他为什么给你做这么多,仔细想想不难看出,这些逻辑是业务场景中重复次数很多的逻辑, vue 不给你做,你自己也要做,还会闲麻烦!当然这还没结束呢!下面更精彩!

为属性 value 和事件 input 命名

有些时候我们可能希望 value 就作为一个普通的属性往下传,而我们的业务场景里面 input 作为事件也不够形象,反正就是 value 和 input 不符合你的业务中的语义,这个时候我想改名,咋办?接下来看下面的代码:

<template>
  <div class="myInput">
    <input type="text" :value="text" @input="inputHandle">
  </div>
</template>

<script>
export default {
  name: "MyInput",
  model: {
    prop: "text", // 该属性名
    event: "update:v-model" // 改事件名
  }
  props: {
    text: String // 即便改名了,这里也必不可少
  },
  methods: {
    inputHandle (event) {
      this.$emit("update:v-model", event.target.value)
    }
  }

}
</script>

上面就展示了我们怎么更名,其实就是改变了 props 中的接受的字段名,然后新增了 model 选项,这里需要注意的是,不管怎么样 props 中的字段都必不可少。

实际应用:父子组件状态同步

如标题所说,这个 api 依然可以用作一些特殊情况下的父子组件状态同步,这里举一个实际的列子,假设我们使用某框架,这个框架提供给我们模态框组件名叫 Modal 这个组件需要添加 v-model 属性来显示隐藏模态框,通常我们的模态框会有很多的逻辑,这个时候我们会考虑将其封装成一个自定义的组件,这个时候我们希望封装过得组件和原来的模态框组件具备相同的使用方式都是加 v-model 来显示隐藏,这是时候我们讲到的功能是不是就特别合适了呢?

我自己建了一个web前端的交流裙有兴趣的可以加入进来交流哦:245650187(免费)237871108(收费)。
个人微信: GD6570 个人球球:718879459 当然你也可以哔哩哔哩搜索木瓜太香
查看原文

赞 0 收藏 0 评论 0

木瓜太香 发布了文章 · 9月14日

DOM监控 MutationObserver | 木瓜太香

DOM监控 MutationObserver

大家好!我是木瓜太香,一个传播webstorm使用技巧的前端工程师,这一次给大家带来的是 DOM 监控的方法。

MutationObserver 接口提供了监视DOM树更改的能力,是旧的 Mutation 的替代品

使用方式:通过 MutationObserver构造函数创建对象 ob,该对象下有以下可用方法

  • observe(dom对象,option) :配置MutationObserver在DOM更改匹配给定选项时,通过其回调函数开始接受通知
  • disconnect():取消监控
  • takeRecords():从MutationObserver的通知队列中删除所有待处理的通知,并将它们返回到 MutationRecord对象的新Array

一个简单的示例

html部分

<div class="container">
    <h1 class="title">一个标题</h1>
    <button class="btn">点击按钮取消监控</button>
</div>

javascript部分

,    let container = document.querySelector('.container');
    let btn = document.querySelector('.btn')

    btn.onclick = function (){
        console.log('监控已经取消');
        observer.disconnect();
    }

    function callback (){
        console.log("回调函数参数");
        console.log(arguments);
    }
    
    let observer = new MutationObserver(callback);

    observer.observe(container,{
        attributes: true // 指定元素属性改变的时候触发回调
    })

详解 observe disconnect takeRecords

  • observe 方法主要指定要监控哪些 DOM 的变化作为第一个参数传入,和要监控哪些地方,使用一个对象描述并作为第二个参数传入

    • 参数一: 要观察的 DOM 或者要观察的所有子节点的公共根节点

      • 参数二:一个可选的 MutationObserverInit对象,此对象的配置项描述了 DOM 的哪些变化要被监控,注意:childListattributes 或者 characterData 三个属性之中,至少有一个必须为 true,否则会抛出 TypeError 异常,实际有attributeFilter也行
    • MutationObserverInit 对象属性

      属性描述
      attributeFilter要监视的特定属性名称的数组。如果未包含此属性,则对所有属性的更改都会触发变动通知。无默认值。
      attributeOldValue当监视节点的属性改动时,将此属性设为 true 将记录任何有改动的属性的上一个值。有关观察属性更改和值记录的详细信息,详见Monitoring attribute values in MutationObserver。无默认值。
      attributes设为 true 以观察受监视元素的属性值变更。默认值为 false
      characterData设为 true 以监视指定目标节点或子节点树中节点所包含的字符数据的变化。无默认值。在监控该类值的时候,传入observe的第一个参数应该是 textNode 而非 element ,不然就需要配合 subtree 使用
      characterDataOldValue设为 true 以在文本在受监视节点上发生更改时记录节点文本的先前值。详情及例子,请查看 Monitoring text content changes in MutationObserver。无默认值。
      childList设为 true 以监视目标节点(如果 subtreetrue,则包含子孙节点)添加或删除新的子节点。默认值为 false
      subtree设为 true 以将监视范围扩展至目标节点整个节点树中的所有节点。MutationObserverInit 的其他值也会作用于此子树下的所有节点,而不仅仅只作用于目标节点。默认值为 false
    • 重复的 observe 调用后面会覆盖前面,前提是第一个参数是相同的,实质上只覆盖了要监控的类型也就是第二个参数
  • disconnect 方法移除监控,如果某个元素从 dom 树中移除那么 MutationObserve 将同样被删除
  • takeRecords 方法返回已检测到但尚未由观察者的回调函数处理的所有匹配DOM更改的列表,使变更队列保持为空。 此方法最常见的使用场景是在断开观察者之前立即获取所有未处理的更改记录,以便在停止观察者时可以处理任何未处理的更改。该方法通常是程序级别的监控,例如设置监控之后立马修改然后调用该方法就可以获取到信息

        let observer = new MutationObserver(callback);
        
        // console.log(container.childNodes);
    
    
        observer.observe(container.childNodes[0], {
            // attributes: true,
            characterData: true,
            characterDataOldValue: true,
            // childList: true,
            // subtree: true
            // attributeFilter: ["class","data-username"],
            // attributeOldValue: true
        })
    
        container.childNodes[0].textContent = "哈哈哈123"
        console.log(observer.takeRecords());

监控到变化之后获取信息:

只监控变化没有用,重要的是我们要知道哪里变了,通常我们可以拿到变化前的老值,新值可以通过具体dom对象获取,关于信息回调函数参数中的 MutationRecord 对象很重要

属性描述
MutationRecord.type如果是属性变化,则返回 "attributes";<br/>如果是 characterData 节点变化,则返回 "characterData";<br/>如果是子节点树 childList 变化,则返回 "childList"
MutationRecord.target根据 MutationRecord.type,返回变化所影响的节点。<br/>对于属性 attributes 变化,返回属性变化的节点。<br/>对于 characterData 变化,返回 characterData 节点。<br/>对于子节点树 childList 变化,返回子节点变化的节点。
MutationRecord.addedNodes返回被添加的节点。<br/>如果没有节点被添加,则该属性将是一个空的 NodeList
MutationRecord.removedNodes返回被移除的节点。<br/>如果没有节点被移除,则该属性将是一个空的 NodeList
MutationRecord.previousSibling返回被添加或移除的节点之前的兄弟节点,或者 null
MutationRecord.nextSibling返回被添加或移除的节点之后的兄弟节点,或者 null
MutationRecord.attributeName返回被修改的属性的属性名,或者 null
MutationRecord.attributeNamespace返回被修改属性的命名空间,或者 null
MutationRecord.oldValue返回值取决于 MutationRecord.type。 对于属性 attributes 变化,返回变化之前的属性值。 对于 characterData 变化,返回变化之前的数据。 对于子节点树 childList 变化,返回 null
注意,如果要让这个属性起作用,在相应的 MutationObserverInit 参数的 MutationObserverobserve 方法中,attributeOldValue 或者 characterDataOldValue 必须设置为 true

特别注意:所有被监控到的更改,其记录的 target 信息都是具体被更改的那个节点对象,如果被更改的是 文本 那么 target 就是一个文本节点。

我自己建了一个web前端的交流裙有兴趣的可以加入进来交流哦:237871108。
个人微信: GD6570 个人球球:718879459 当然你也可以哔哩哔哩搜索木瓜太香
查看原文

赞 0 收藏 0 评论 0

木瓜太香 发布了文章 · 9月12日

深入理解 vue 中 scoped 样式作用域的规则

哈喽!大家好!我是木瓜太香,今天我们来聊一个 vue 的样式作用域的问题,通常我们开发项目的时候是要在 style 上加上 scoped 来起到规定组件作用域的效果的,所以了解他们的规则也是很有必要的,可以让你更清晰的了解你的项目样式是怎么运作的。

先来说说实现方式

vue中的样式作用域是通过属性选择器来实现的,例如同样一个类名,我们是通过 .类名[属性名] 来做区分的,我们这里主要是要搞清楚这里的属性名是怎么分配的。

样式作用域规则

接下来我们分情况来说一下样式作用域:

  • 对于有样式作用域的组件,该组件的所有后代元素都会具备一个相同的作用域属性,而该组件的内部的根元素除了具备当前组件作用域属性也会具备其父级组件的作用域,当然如果父级没有作用域则不具备
  • 对于没有样式作用域的组件,如果父组件是有作用域的,那么该组件只有根元素会继承父组价的作用域,其后代的元素不会有作用域
  • 对于处在同一层次的组件,其作用域是相同的,从下一代开始才会有所区别
  • 特别要注意的是对于组件的复用,在当前项目,不管是什么层级,复用的组件作用域都相同

样式作用域图示

作用域图示

实际应用效果

有了基本的样式作用域知识储备之后,接下来我们来看一下 vue 最终会怎么将这些样式作用域应用到选择器的。

对于单个的选择器 .box[data-v-abc] 对于复合选择器:.box a[data-v-abc].box[data-v-abc],.wrap[data-v-abc].box > div[data-v-abc]

根据上面的知识储备,我们就知道,如果组件都只被引用一次,通常是不存在样式干扰的,但是如果一个组件在一个页面中复用多次,依然是有样式干扰的可能。

我自己建了一个web前端的交流裙有兴趣的可以加入进来交流哦:237871108。
个人微信: GD6570 个人球球:718879459 当然你也可以哔哩哔哩搜索木瓜太香
查看原文

赞 1 收藏 1 评论 0

木瓜太香 发布了文章 · 9月10日

javascript事件环微任务和宏任务队列原理

哈喽!大家好!我是木瓜太香,我又来嘞,今天来说说前端面试中经常别问到的 JS 事件环问题。

JS 事件环

JS 程序的运行是离不开事件环机制的,这个机制保证在发生某些事情的时候我们有机会执行一个我们事先预定好的函数,事情发生的时候 JS 会将相应的函数入栈执行然后出栈,但是关于事件环我们还有一些未知的东西,例如,setTimeout 我们习惯称他为定时器,但是可能很多人没有意识到,这个东西和我们常用的一些事件没什么不同,只不过我们通常所说的事件大多需要用户触发,而 setTimeout 不用用户自己触发,而是指定时间之后触发;那么问题来了,如果我们将时间设置为 0 会发生什么?会立即执行么?

setTimeout、DOM或者 HTTP请求这部分其实并不在 v8 引擎中,这些属于 web API,javascript 是一个单线程的语言,也就意味着一次只能做一件事情,这个事实从未改变

执行原理

JS 中所有的方法都会被推入栈中执行,执行完成被弹出,在遇到异步代码的时候,例如 setTimeout MutationObserver Promise 异步的部分会由其他掌管 webAPI 的地方执行,等异步有结果之后,回调函数会进入相应的队列,Promise MutationObserver 回调进入微任务队列,setTimeout setInterval requestAnimationFrame 进入宏任务队列。等待主线程的执行栈空了,微任务队列立刻被推入栈中执行,执行完毕开始执行宏任务队列

未命名文件

一个经典的例子

html

<div class="outer">
  <div class="inner"></div>
</div>

js

// Let's get hold of those elements
var outer = document.querySelector('.outer');
var inner = document.querySelector('.inner');

// Let's listen for attribute changes on the
// outer element
new MutationObserver(function () {
  console.log('mutate');
}).observe(outer, {
  attributes: true,
});

// Here's a click listener…
function onClick() {
  console.log('click');

  setTimeout(function () {
    console.log('timeout');
  }, 0);

  Promise.resolve().then(function () {
    console.log('promise');
  });

  outer.setAttribute('data-random', Math.random());
}

// …which we'll attach to both elements
inner.addEventListener('click', onClick);
outer.addEventListener('click', onClick);

以上代码在,手动点击 inner 元素的时候会有如下输出

click
promise
mutate
click
promise
mutate
timeout
timeout

截止 2020年8月份 chrome edge opera firefox 的结果是统一的,但是在此之前的版本可能会有不同的输出。

一个奇怪的现象

上述代码我们不使用手动触发点击,而是使用 inner.click() 触发点击,其结果会有很大的不同

click
click
promise
mutate
promise
timeout
timeout

造成以上巨大差异的原因是,手动点击,不是通过函数进入执行栈的方式触发点击事件的回调,所以inner 的回调执行完了主线程中的执行栈就是空的可以直接执行队列中任务,然后事件冒泡导致的回调函数才被推入栈运行;而 click 方法的点击则是通过将 click 推入栈中执行来达到的,inner 的点击回调执行完了之后 click 方法并没有被弹出栈,而是直接执行冒泡的下一个回调,由于下一个回调有一个重复的 属性设置 这是不会重复触发 MutationObserver的所以 mutate 的输出只会有一个。等所有的冒泡回调被执行完毕 click 函数才会被弹出栈。

最后注意,浏览器会尽量预先执行较为敏感的操作。

我自己建了一个web前端的交流裙有兴趣的可以加入进来交流哦:237871108。当然你也可以通过哔哩哔哩搜索木瓜太香找到我。
查看原文

赞 0 收藏 0 评论 0

木瓜太香 发布了文章 · 9月10日

webstorm单标签设置成双标签展开解决iview中col展开问题

大家好!我是木瓜太香,今天给大家带来一个 webstorm 小技巧

场景:有使用过 vue 框架并且使用 iview 做 ui webstorm 做 ide 的同学,可能会遇到一个比较奇怪的问题,iview 中有一个 Col 的组件,这个组件作为一个布局组件存在,但是他和 html 原生标签 col 重复了,iview 中 Col 需要是双标签,原生 html 中 col 是单标签,webstorm 就会认为他是单标签,在展开的时候也就只是单标签了。

解决的办法其实比较简单,我们可以在 webstorm 中的 live template 中新建一个 Col 项 指定内容为 <Col>$END$</Col> 这样我们在展开就是双标签了,如果你还不知道怎么添加 live template 可以去B站看一下我录的视频,有详细教学。

我自己建了一个web前端的交流裙有兴趣的可以加入进来交流哦:237871108。当然你也可以通过哔哩哔哩搜索木瓜太香找到我。
查看原文

赞 0 收藏 0 评论 0

木瓜太香 发布了文章 · 9月9日

vue父子组件状态同步的最佳方式

哈喽!大家好!我是木瓜太香,一位老牌儿前端工程师,平时我们在使用 vue 开发的时候,可能会遇到需要父组件与子组件某个状态需要同步的情况,通常这个是因为我们封装组件的时候有一个相同的状态外面要用,里面也要用,今天我们就来看看怎么优雅的解决这个问题吧!

一般来说我们实现这个功能,只需要父组件通过 props 传递给子组件就好了,但是理想很丰满,现实很骨感,如果我们直接在子组件更改传进来的 props ,不出意外浏览器会给你一坨大红色的报错,因为在 vue 中我们的数据流动是自上而下的,而子组件直接更改父组件传来的 props 则是自下而上的数据流动,这是 vue 不允许的。

所以通常我们的解决办法是,父组件通过 props 传入状态给子组件,子组件通过 props 来初始化另外一个内部的状态,子组件每次更改状态之后都通知父组件,然后由父组件来更改自己的状态,其实就是 props on emit 的应用,接下来我们来上代码。

父组件 Father.vue

<template>
    <div class="father">
        <h1>父组件维护的状态:{{food}}</h1>
        <son :food="food" @update:food="f => food = f"></son>
    </div>
</template>

子组件 Son.vue

<template>
    <div class="son">
        <h2>子组件中维护的状态:{{innerFood}}</h2>
        <button @click="innerFood = '100斤牛肉'">点击更改子组件状态</button>
    </div>
</template>
<script>
    export default {
        data () {
          return {
              innerFood: this.food
          }  
        },
        props: {
            food: String
        },
        watch: {
            innerFood (nv) {
                this.$emit("update:food",nv)
            }
        }
    }
</script>

可以看到我们上述的写法,其实是维护了父子组件中的不同的两个状态,我们做的工作只是将这两个状态同步了,这种写法没有任何问题,其实对于子组件的部分我们也可以通过 computed 来实现,下面我们来看一看另一种子组件内维护同步状态的方法:

子组件 Son.vue 的另一种写法

<template>
    <div class="son">
        <h2>子组件中维护的状态:{{innerFood}}</h2>
        <button @click="innerFood = '100斤牛肉'">点击更改子组件状态</button>
    </div>
</template>
<script>
    export default {
        props: {
            food: String
        },
        computed: {
            innerFood: {
                get () {
                    return this.food
                },
                set (nv) {
                    this.$emit("update:food",nv)
                }
            }
        }
    }
</script>

好了,两种写法我们都已经演示完毕,现在我们来优化一下父组件中的写法。

父组件中可以看到我们之前在上面绑定了一个 update:food 事件,并且使用箭头函数做了一个赋值,其实这里我们可以稍微优化一下,不要箭头函数直接赋值,因为我们触发的是自定义事件,而我们触发的时候给的第一个参数就是新值,我们可以直接通过 $event 拿到这个值,所以可以写成如下形式:

优化后的父组件

<template>
    <div class="father">
        <h1>父组件维护的状态:{{food}}</h1>
        <son :food="food" @update:food="food = $event"></son>
    </div>
</template>

到这里你以为就结束了?其实我们还可以更近一步,只要满足我们以上的事件命名方式,我们实际上可以使用 sync 修饰符代替事件的绑定,也就是我们不用写事件绑定了,但是子组件内部的事件触发依然不能少,最终优化的结果如下:

<template>
    <div class="father">
        <h1>父组件维护的状态:{{food}}</h1>
        <son :food.sync="food"></son>
    </div>
</template>

到此我们就真的完成了父子组件的同步,当然在子组件中维护一个状态不一定是必须的,如果我们只用父组件传给我们的 props 做展示,而子组件没有对这个 props 直接更改的行为,那么我们就不用在子组件创建另外一个状态,我们子组件想改他的时候只需要在合适的时机提交合适的事件即可,但是有一种情况我们不得不在子组件中创建另一个状态,就是我们父组件传入的状态在子组件中用于 v-model 这种双向数据绑定的功能时,由于 v-model 会自动更改值所以直接填入从父组件接受的 props 就不合适了。

我自己建了一个web前端的交流裙有兴趣的可以加入进来交流哦:237871108。当然你也可以通过哔哩哔哩搜索木瓜太香找到我。
查看原文

赞 0 收藏 0 评论 0

木瓜太香 发布了文章 · 9月8日

webstorm编写vue、react 将大驼峰组件命名转换成短横杠命名

大家好!我是木瓜太香,精通 webstorm 与常见前端技术的工程师,偶尔也在b站搞一些 webstorm 技巧教学,今天给大家带来的是大驼峰小驼峰快速转换短横杠命名或者下划线命名的方式。

开发中我们可能会遇到一个这样的需求,我们在创建组件的时候习惯使用大驼峰命名,而在使用的时候,我们又要使用短横杠或者下划线命名,这种功能我们当然不可能手打的啦,这辈子都不可能的啦。

解决的办法一般比较容易想到的有两种,一种是直接使用插件实现,另一种则是使用宏命令来实现,两种都是可以完成这个操作的,只是第二种更加考验大家对 webstorm 的使用熟练度,所以今天我们先来讲讲这第一种,插件实现方式。

这里我们用到的插件名是 String Manipulation 我们在 webstorm 中安装该插件之后,重启 webstorm 就可以使用了。

使用的方式是对你想转换的字符串右键选中 String Manipulation | Switch Case | 这个路径下面有很多各种各样的选项,可以根据需要来转换。

当然鼠标操作,肯定以及一定还不够快捷,这个时候快捷键绑定就派上用场了,去快捷键绑定一下对应的命令吧,什么?还不会快捷键的绑定?那还不快去哔哩哔哩看木瓜太香的教程!!!

我自己建了一个web前端的交流裙有兴趣的可以加入进来交流哦:237871108。当然你也可以通过哔哩哔哩搜索木瓜太香找到我。
查看原文

赞 0 收藏 0 评论 0

木瓜太香 发布了文章 · 9月7日

vue、react等SPA应用页脚组件闪烁的解决办法

大家好,我是木瓜太香。大家在开发单页应用的时候,经常会遇到这样的需求,头部和尾部两个组件是大多数组件公用的,而中间的内容区域则是单独存在的,而且一般内容组件逻辑会比较多,如果我们不停刷新页面可能会出现尾部组件闪烁的问题。

这个问题的出现主要是因为,内容区组件要比尾部组件大,而且尾部组件一般是没有什么逻辑的,相当于一个静态组件。

解决这个问题的思路就是想办法在页面最开始加载的时候隐藏尾部组件,之后再合适的时候将尾部组件显示出来即可。

说一下公司项目(VUE)中的解决办法,我们的思路是,先让尾部组件固定定位到页面外部,这样在最开始加载的时候就看不到尾部组件,然后我们通过监听路由变化来让组件显示,具体做法如下。

  1. 定义类名 .footer-fixed 将该类名添加到 footer 组件上

    .footer-fixed {
      position: fixed;
      bottom: -200px;
    }
  2. 利用 vue 中的 watch 监听路由,恢复 footer组件的显示

        $route: {
          handler () { // 组件加载完成之后将隐藏的底部显示出来
             const footerDom = document.getElementsByClassName('footer')[0]
             footerDom.classList.remove('footer-fixed')
          }
        }

当然你也可以使用路由的全局后置守卫做到同样的效果,不过我们当时考虑到的是逻辑相关性,所以才采用监控的方式。

更多前端技巧可以关注一下哔哩哔哩:木瓜太香

我自己建了一个web前端的交流裙有兴趣的可以加入进来交流哦:237871108。当然你也可以通过哔哩哔哩搜索木瓜太香找到我。
查看原文

赞 0 收藏 0 评论 0

木瓜太香 发布了文章 · 9月6日

webstorm中emmet展开a标签和行内元素不换行的解决办法

大家好我是木瓜太香,大家在使用 webstorm 编写 html 的时候可能会遇到展开部分标签挨在一起的情况,相信很多小伙伴都想解决这个问题,接下来我们就开始吧!

先来看看我们输入如下 emmet 代码的时候展开的效果是怎么样的

div>a*3

展开效果:

image-20200906221037752

这个时候我们可能需要自己去一个一个回车排版,当然这肯定不是你想要的,现在我们来解决这个问题。

在解决问题之前,我们要知道产生这个问题的原因,在 webstorm 中是对标签进行分类的,其实从逻辑上来说,a 标签这种本身就属于行内标签,不换行在逻辑上是没有任何问题的,但是我们开发的时候经常需要根据情况来调整,因为很多时候 a 标签会写的很长,我们更希望换行来增加可读性。

解决办法: 将 a 标签在 webstorm 中的分类变成非行内标签即可。

设置路径:File | Settings | Editor | Code Style | HTML | Other

找到上述路径对应的页面之后,向下翻动,找到 Inline elements 这个选项,将右边输入框中的 a 标签删除掉,之后保存设置即可,其他的行内标签也是同样的修改方法。

image-20200906221921697

经过以上的修改我们最终展开的效果如下图:

image-20200906222102921

好了这个问题到这里我们就解决了,如果大家有更多 webstorm 上的疑问,或者想学习更过 webstorm 相关的技巧,可以去哔哩哔哩搜索:木瓜太香 。(PS:目前应该是对 webstorm 做的最全的了)

我自己建了一个web前端的交流裙有兴趣的可以加入进来交流哦:237871108。当然你也可以通过哔哩哔哩搜索木瓜太香找到我。
查看原文

赞 0 收藏 0 评论 0

木瓜太香 发布了文章 · 9月6日

DOM监控 MutationObserver | 木瓜太香

DOM监控 MutationObserver

大家好!我是木瓜太香,一个传播webstorm使用技巧的前端工程师,这一次给大家带来的是 DOM 监控的方法。

MutationObserver 接口提供了监视DOM树更改的能力,是旧的 Mutation 的替代品

使用方式:通过 MutationObserver构造函数创建对象 ob,该对象下有以下可用方法

  • observe(dom对象,option) :配置MutationObserver在DOM更改匹配给定选项时,通过其回调函数开始接受通知
  • disconnect():取消监控
  • takeRecords():从MutationObserver的通知队列中删除所有待处理的通知,并将它们返回到 MutationRecord对象的新Array

一个简单的示例

html部分

<div class="container">
    <h1 class="title">一个标题</h1>
    <button class="btn">点击按钮取消监控</button>
</div>

javascript部分

,    let container = document.querySelector('.container');
    let btn = document.querySelector('.btn')

    btn.onclick = function (){
        console.log('监控已经取消');
        observer.disconnect();
    }

    function callback (){
        console.log("回调函数参数");
        console.log(arguments);
    }
    
    let observer = new MutationObserver(callback);

    observer.observe(container,{
        attributes: true // 指定元素属性改变的时候触发回调
    })

详解 observe disconnect takeRecords

  • observe 方法主要指定要监控哪些 DOM 的变化作为第一个参数传入,和要监控哪些地方,使用一个对象描述并作为第二个参数传入

    • 参数一: 要观察的 DOM 或者要观察的所有子节点的公共根节点

      • 参数二:一个可选的 MutationObserverInit对象,此对象的配置项描述了 DOM 的哪些变化要被监控,注意:childListattributes 或者 characterData 三个属性之中,至少有一个必须为 true,否则会抛出 TypeError 异常,实际有attributeFilter也行
    • MutationObserverInit 对象属性

      属性描述
      attributeFilter要监视的特定属性名称的数组。如果未包含此属性,则对所有属性的更改都会触发变动通知。无默认值。
      attributeOldValue当监视节点的属性改动时,将此属性设为 true 将记录任何有改动的属性的上一个值。有关观察属性更改和值记录的详细信息,详见Monitoring attribute values in MutationObserver。无默认值。
      attributes设为 true 以观察受监视元素的属性值变更。默认值为 false
      characterData设为 true 以监视指定目标节点或子节点树中节点所包含的字符数据的变化。无默认值。在监控该类值的时候,传入observe的第一个参数应该是 textNode 而非 element ,不然就需要配合 subtree 使用
      characterDataOldValue设为 true 以在文本在受监视节点上发生更改时记录节点文本的先前值。详情及例子,请查看 Monitoring text content changes in MutationObserver。无默认值。
      childList设为 true 以监视目标节点(如果 subtreetrue,则包含子孙节点)添加或删除新的子节点。默认值为 false
      subtree设为 true 以将监视范围扩展至目标节点整个节点树中的所有节点。MutationObserverInit 的其他值也会作用于此子树下的所有节点,而不仅仅只作用于目标节点。默认值为 false
    • 重复的 observe 调用后面会覆盖前面,前提是第一个参数是相同的,实质上只覆盖了要监控的类型也就是第二个参数
  • disconnect 方法移除监控,如果某个元素从 dom 树中移除那么 MutationObserve 将同样被删除
  • takeRecords 方法返回已检测到但尚未由观察者的回调函数处理的所有匹配DOM更改的列表,使变更队列保持为空。 此方法最常见的使用场景是在断开观察者之前立即获取所有未处理的更改记录,以便在停止观察者时可以处理任何未处理的更改。该方法通常是程序级别的监控,例如设置监控之后立马修改然后调用该方法就可以获取到信息

        let observer = new MutationObserver(callback);
        
        // console.log(container.childNodes);
    
    
        observer.observe(container.childNodes[0], {
            // attributes: true,
            characterData: true,
            characterDataOldValue: true,
            // childList: true,
            // subtree: true
            // attributeFilter: ["class","data-username"],
            // attributeOldValue: true
        })
    
        container.childNodes[0].textContent = "哈哈哈123"
        console.log(observer.takeRecords());

监控到变化之后获取信息:

只监控变化没有用,重要的是我们要知道哪里变了,通常我们可以拿到变化前的老值,新值可以通过具体dom对象获取,关于信息回调函数参数中的 MutationRecord 对象很重要

属性描述
MutationRecord.type如果是属性变化,则返回 "attributes";<br/>如果是 characterData 节点变化,则返回 "characterData";<br/>如果是子节点树 childList 变化,则返回 "childList"
MutationRecord.target根据 MutationRecord.type,返回变化所影响的节点。<br/>对于属性 attributes 变化,返回属性变化的节点。<br/>对于 characterData 变化,返回 characterData 节点。<br/>对于子节点树 childList 变化,返回子节点变化的节点。
MutationRecord.addedNodes返回被添加的节点。<br/>如果没有节点被添加,则该属性将是一个空的 NodeList
MutationRecord.removedNodes返回被移除的节点。<br/>如果没有节点被移除,则该属性将是一个空的 NodeList
MutationRecord.previousSibling返回被添加或移除的节点之前的兄弟节点,或者 null
MutationRecord.nextSibling返回被添加或移除的节点之后的兄弟节点,或者 null
MutationRecord.attributeName返回被修改的属性的属性名,或者 null
MutationRecord.attributeNamespace返回被修改属性的命名空间,或者 null
MutationRecord.oldValue返回值取决于 MutationRecord.type。 对于属性 attributes 变化,返回变化之前的属性值。 对于 characterData 变化,返回变化之前的数据。 对于子节点树 childList 变化,返回 null
注意,如果要让这个属性起作用,在相应的 MutationObserverInit 参数的 MutationObserverobserve 方法中,attributeOldValue 或者 characterDataOldValue 必须设置为 true

特别注意:所有被监控到的更改,其记录的 target 信息都是具体被更改的那个节点对象,如果被更改的是 文本 那么 target 就是一个文本节点。

我有建立qun来让大家讨论前端相关问题,237871108
哔哩哔哩也可以搜索木瓜太香找到我。

查看原文

赞 0 收藏 0 评论 0

木瓜太香 关注了用户 · 9月5日

烟雨星空 @starryskys_softwindwith

目前从事Java开发,喜欢游戏,业余时间自学游戏开发。
个人公众号「烟雨星空」,关注可免费领取1000G的学习大礼包,含前端,Java,大数据,Python,人工智能等资料。

关注 457

木瓜太香 关注了专栏 · 9月5日

SegmentFault 行业快讯

第一时间为开发者提供行业相关的实时热点资讯

关注 28092

木瓜太香 关注了专栏 · 9月5日

网易云音乐大前端团队

网易云音乐大前端技术团队专栏

关注 1624

木瓜太香 关注了用户 · 9月5日

子君 @zijun_5f156624be160

微信公众号: 前端有得玩
微信账号:snowzijun
github仓库: https://github.com/snowzijun
寄语:不要吹灭你的灵感和你的想象力; 不要成为你的模型的奴隶。

关注 552

木瓜太香 关注了用户 · 9月5日

前端劝退师 @xiaowangbingpbingp_5f16ba8c72a4b

关注 178

木瓜太香 关注了专栏 · 9月5日

X先生说

分享我的技术笔记,思考记录

关注 429

木瓜太香 关注了专栏 · 9月5日

前端巅峰

注重前端性能优化和前沿技术,重型跨平台开发,即时通讯技术等。 欢迎关注微信公众号:前端巅峰

关注 16738

木瓜太香 关注了专栏 · 9月5日

全栈修仙之路

聚焦全栈,专注分享 Angular、TypeScript、Node.js/Java 、Spring 技术栈等全栈干货。 欢迎小伙伴们关注公众号全栈修仙之路,一起升级打怪。

关注 7027

木瓜太香 关注了专栏 · 9月5日

大前端架构设计

专注大前端架构设计。

关注 351