使用 vanilla javascript 在 React 页面中添加元标记

Add a meta tag in React page with vanila javascript

我想在没有外部库的情况下使用普通 javascript 在 React 组件上添加元标记。我已将其添加到 useEffect 挂钩中,如下所示:

 useEffect(() => {
    const ogTitle = document.createElement('meta');
    const ogImage = document.createElement('meta');
    const ogDescription = document.createElement('meta');
    if(classPage?.name) {
     
      ogTitle.setAttribute('property', 'og:title');
      ogTitle.content= classPage?.name;
      document.getElementsByTagName('head')[0].appendChild(ogTitle);
    }

   if(classPage?.pictureUrl) {
    
     ogImage.setAttribute('property', 'og:image');
     ogImage.content= classPage?.pictureUrl;
     document.getElementsByTagName('head')[0].appendChild(ogImage);
   }
    
   if(classPage?.description) {
     ogDescription.setAttribute('property', 'og:description');
     ogDescription.content= classPage?.description;
     document.getElementsByTagName('head')[0].appendChild(ogDescription);
   }
  
     const ogUrl = document.createElement('meta');
     ogUrl.setAttribute('property', 'og:url');
     ogUrl.content = document.location.href;
     document.getElementsByTagName('head')[0].appendChild(ogUrl);
   

  }, [classPage]);

当我打开 chrome 检查器时我可以看到结果,它们在 head 标签中。但是当我转到其他页面时,我看到元标记附加在下面,而不是替换上一页中的值。像这样:

<meta property="og:url" content="http://localhost:3000/ClassReadOnly/testing21186f6938be44682b8ccdc95827344b5">
<meta property="og:title" content="Testing 2">
<meta property="og:image" content="https://images.unsplash.com/photo-1616008783091-189d8c5efd61?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxODkyMzl8MHwxfHJhbmRvbXx8fHx8fHx8fDE2MjEzMzUzMzY&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1080">
<meta property="og:description" content="testing">
<meta property="og:url" content="http://localhost:3000/ClassReadOnly/testing21186f6938be44682b8ccdc95827344b5">
<meta property="og:url" content="http://localhost:3000/ClassReadOnly/myfirstclasscc319a1ab57e4874be991a346e6fa86e">
<meta property="og:title" content="My First Class">
<meta property="og:image" content="https://images.unsplash.com/photo-1623001398544-5c7f047842ca?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxODkyMzl8MHwxfHJhbmRvbXx8fHx8fHx8fDE2MjM4NjAwMjA&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1080">
<meta property="og:description" content="jhlghjul iuiuiu iouiuii">
<meta property="og:url" content="http://localhost:3000/ClassReadOnly/myfirstclasscc319a1ab57e4874be991a346e6fa86e">
<meta property="og:url" content="http://localhost:3000/ClassReadOnly/testing21186f6938be44682b8ccdc95827344b5">
<meta property="og:title" content="Testing 2">
<meta property="og:image" content="https://images.unsplash.com/photo-1616008783091-189d8c5efd61?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxODkyMzl8MHwxfHJhbmRvbXx8fHx8fHx8fDE2MjEzMzUzMzY&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1080">
<meta property="og:description" content="testing">
<meta property="og:url" content="http://localhost:3000/ClassReadOnly/testing21186f6938be44682b8ccdc95827344b5">

我试过这样的清理功能:

return () => {
  ogTitle.removeAttribute('property')
  ogTitle.content = '';
  document.getElementsByTagName('head')[0].removeChild(ogTitle)
  ......
}

但是出现这个错误:

NotFoundError: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.

所以我的问题是如何使用普通 javascript、无库

在 React 组件中添加元标记

您的清理函数是:

  1. 正在创建一个新的元元素
  2. 从中删除 属性 属性(即使它没有)
  3. 设置内容属性为空字符串
  4. 尝试将其从头部移除(即使您一开始从未将其添加到头部)

如果要删除之前添加到 DOM 的元素,则需要获取对该元素的引用。

正在创建一个新元素…创建一个新元素。它没有找到现有的。

您已经引用了 ogTitle 中的元元素和您创建的其他变量。使用那些。

您应该直接在清理回调中删除附加的元元素。

useEffect(() => {
  const ogTitle = document.createElement('meta');
  const ogImage = document.createElement('meta');
  const ogDescription = document.createElement('meta');

  if(classPage?.name) { 
    ogTitle.setAttribute('property', 'og:title');
    ogTitle.content= classPage?.name;
    document.getElementsByTagName('head')[0].appendChild(ogTitle);
  }

  if(classPage?.pictureUrl) {
    ogImage.setAttribute('property', 'og:image');
    ogImage.content= classPage?.pictureUrl;
    document.getElementsByTagName('head')[0].appendChild(ogImage);
  }
    
  if(classPage?.description) {
    ogDescription.setAttribute('property', 'og:description');
    ogDescription.content= classPage?.description;
    document.getElementsByTagName('head')[0].appendChild(ogDescription);
  }

  const ogUrl = document.createElement('meta');
  ogUrl.setAttribute('property', 'og:url');
  ogUrl.content = document.location.href;
  document.getElementsByTagName('head')[0].appendChild(ogUrl);
 
  return () => {
    for (const metaElement of [ogTitle, ogImage, ogDescription, ogUrl]) {
      metaElement.parentNode.removeChild(metaElement)
    }
  }
}, [classPage]);

如前所述,问题似乎是您每次都在创建元素。在我看来,制作一个 meta adder 函数是一个好主意,如下所示:

const metaAdder = (queryProperty, value) => {
  // Get an element if it exists already
  let element = document.querySelector(`meta[${queryProperty}]`);

  // Check if the element exists
  if (element) {
    // If it does just change the content of the element
    element.setAttribute("content", value);
  } else {
    // It doesn't exist so lets make a HTML element string with the info we want
    element = `<meta ${queryProperty} content="${value}" />`;

    // And insert it into the head
    document.head.insertAdjacentHTML("beforeend", element);
  }
};

然后您可以调用此函数并传递您希望更改的元标记的 property/name 以及值。如果元标记存在,它将更改内容,否则将创建并插入它。

在你的例子中:

  if(classPage?.name) { 
    metaAdder('property="og:title"', classPage.name)
  }

我已经删除了你对 className 是否存在的第二次检查,因为我们已经在包装 if 语句中检查过了。

如果您希望更改 属性 内容以外的内容,您可以更改函数以获取对象。