当サイトは、アフィリエイト広告を利用しています
このブログにはgoolgeAdsenseで広告をつけているのだが、
よく広告が未取得( data-ad-status="unfilled" )になり謎の空白ができてしまう
時があり、何とか未取得の場合に非表示にできないか調べたところ、
GoogleAdSenseヘルプにMutationObserverを使えとあったので
MutationObserverの動きを簡単に試してみた。
MutationObserverは監視するDOM要素とコールバック関数を設定すれば
監視してるDOM要素に変更があった場合、コールバック関数を実行できる。
基本的な使い方はコールバック関数を引数にしてMutationObserverオブジェクトを作って
オブジェクトに監視対象要素を設定する
~//オプションconst options = {childList: true, //直接の子の変更を監視characterData: true, //文字の変化を監視characterDataOldValue: true, //属性の変化前を記録attributes: true, //属性の変化を監視subtree: true //全ての子要素を監視};// 変更検知時のコールバック関数const callback = (mutationsList) => {mutationsList.forEach((element) => {// 任意の処理console.log(element);console.log(element.target.id);console.log(element.target.className);});};//MutationObserverオブジェクト生成const obs = new MutationObserver(callback);//ターゲット要素の監視を開始//ターゲット要素をuseRefで設定obs.observe(sampleRef.current, options);// クリーンアップで監視を停止return () => obs.disconnect();}, []);~
監視オプションを設定する。
詳しくはMutation observerを参照
監視対象DOM要素の変更を検知した時に実行される関数。
引数としてDOM に生じた個々の変更を保持したMutationRecordのリストが渡されるので
それを元に処理を行う。
MutationRecordの詳細はMutationRecordを参照。
コールバック関数を引数にしてMutationObserverオブジェクトを生成する。
MutationObserverオブジェクトのobserveメソッドに下記を渡して
監視を開始させる。
監視を終了する
React + EmotionでMutationObserverを使ったサンプルを実装して
動きを確認する。
changeColorボタンを押せば色が変わるだけの簡単なサンプル。
このボタンを押したタイミングで監視対象のDOM要素のclassをEmotionで付け替える。
/** @jsxImportSource @emotion/react */import { css } from "@emotion/react";import "./styles.css";import { useState, useEffect, useRef } from "react";export default function App() {// DOM要素取得のためconst sampleRef = useRef(null);const [flg, setFlg] = useState(false);const handleClick = () => {setFlg((prevFlg) => !prevFlg);};useEffect(() => {//オプションconst options = {// childList: true, //直接の子の変更を監視// characterData: true, //文字の変化を監視// characterDataOldValue: true, //属性の変化前を記録attributes: true, //属性の変化を監視// subtree: true //全ての子要素を監視};// 変更検知時のコールバック関数const callback = (mutationsList) => {mutationsList.forEach((element) => {// 任意の処理console.log(element);console.log(element.target.id);console.log(element.target.className);});};//インスタンス化const obs = new MutationObserver(callback);//ターゲット要素の監視を開始//ターゲット要素をuseRefで設定obs.observe(sampleRef.current, options);// クリーンアップで監視を停止return () => obs.disconnect();}, []);return (<div className="App"><h1 id="1" ref={sampleRef} css={flg ? [style1] : [style2]}>Hello CodeSandbox</h1><h2>react + emotion</h2><h2>MutationObserver</h2><button onClick={() => handleClick()}>changeColor</button></div>);}const style1 = () => [css`color: red;`];const style2 = () => [css`color: blue;`];
codesandboxで動作確認する
実際にMutationObserverを使ってAdSenseがdata-ad-status="unfilled"になり
広告未配信の場合に広告を非表示にするようGoogleAdSense表示用コンポーネントを
編集する
import React, { useEffect, useRef, useState } from 'react';import { css } from 'twin.macro';import { isMobile } from 'react-device-detect';const Adsense = props => {const { currentPath, type } = props;const adRef = useRef(null); // 広告要素取得const [dispFLg, setFlg] = useState(true); // 広告表示不フラグuseEffect(() => {if (window) {// mobileの場合は表示後に読み込むif (isMobile) {window.onload = function() {window.adsbygoogle = window.adsbygoogle || [];window.adsbygoogle.push({});};} else {window.adsbygoogle = window.adsbygoogle || [];window.adsbygoogle.push({});}}}, [currentPath]);// 広告が未配信の場合に非表示にするuseEffect(() => {// オプションconst options = {attributes: true, // 属性の変化を監視attributeFilter: ['data-ad-status'], // 指定した属性を監視};// 変更検知時のコールバック関数const callback = mutationsList => {mutationsList.forEach(element => {// 未配信(data-ad-status === "unfilled)の場合if (element.target.attributes['data-ad-status'].value === 'unfilled') {setFlg(false);}});};// インスタンス化const obs = new MutationObserver(callback);// ターゲット要素の監視を開始// ターゲット要素をuseRefで設定obs.observe(adRef.current, options);// クリーンアップで監視を停止return () => obs.disconnect();}, []);const adsence = () => {switch (type) {case 'display':return (// dispFLgがfalseの場合にunfilledでスタイルを設定する<div css={[dispFLg || unfilled]}><insref={adRef}className="adsbygoogle"style={{ display: 'block' }}data-ad-client="ca-pub-xxxxxxxxxxxxxxxx"data-ad-slot="xxxxxxxxxx"data-ad-format="auto"data-full-width-responsive="true"/></div>);case 'infeed':return (<div css={[dispFLg || unfilled]}><insref={adRef}className="adsbygoogle"style={{ display: 'block' }}data-ad-format="fluid"data-ad-layout-key="xxxxxxxxxx"data-ad-client="ca-pub-xxxxxxxxxxxxxxxx"data-ad-slot="xxxxxxxxxx"/></div>);case 'mdx':return (<div css={[dispFLg || unfilled]}><insref={adRef}className="adsbygoogle"style={{ display: 'block' }}data-ad-layout="in-article"data-ad-format="fluid"data-ad-client="ca-pub-xxxxxxxxxxxxxxxx"data-ad-slot="xxxxxxxxxx"/></div>);case 'Multiplex_column':return (<div css={[dispFLg || unfilled]}><insref={adRef}className="adsbygoogle"style={{ display: 'block' }}data-ad-format="autorelaxed"data-ad-client="ca-pub-xxxxxxxxxxxxxxxx"data-ad-slot="xxxxxxxxxx"/></div>);case 'Multiplex_row':return (<div css={[dispFLg || unfilled]}><insref={adRef}css={[dispFLg || unfilled]}className="adsbygoogle"style={{ display: 'block' }}data-ad-format="autorelaxed"data-ad-client="ca-pub-xxxxxxxxxxxxxxxx"data-ad-slot="xxxxxxxxxx"/></div>);case 'display_sq':return (<div css={[dispFLg || unfilled]}><insref={adRef}css={[dispFLg || unfilled]}className="adsbygoogle"style={{ display: 'block' }}data-ad-slot="xxxxxxxxxx"data-ad-format="auto"data-full-width-responsive="true"/></div>);default:return (<div css={[dispFLg || unfilled]}><insref={adRef}css={[dispFLg || unfilled]}className="adsbygoogle"style={{ display: 'block' }}data-ad-client="ca-pub-xxxxxxxxxxxxxxxx"data-ad-slot="xxxxxxxxxx"data-ad-format="auto"data-full-width-responsive="true"/></div>);}};return <div>{adsence()}</div>;};export default Adsense;// 非表示にする関数(Emotionで指定)const unfilled = () => [css`display: none;`,];
Gatsby製ブログにAdSense広告をつける方法について下記記事でまとめています
サンプルを作ってみることでMutationObserverの動きは理解できた。
使い方としては監視領域と監視要素の交差を検知してコールバック関数を実行できる
intersection observer apiと同じような感じでした。
Reactで使う場合はhooksのuseState,useRef,useEffectと併用する必要がありそう。
直接DOMをいじることもできそうだが、React的にはあまりよくなさそうなので...
下記を参考にさせて頂きました。