React重新渲染的触发机制及其优化策略

2023-11-18

React是一个用于构建用户界面的JavaScript库,它的核心特点之一是使用虚拟DOMVirtual DOM)来实现高效的组件渲染。那组件重新渲染的机制是如何呢?基于这些机制,如果进行优化呢?

在这里插入图片描述

虚拟DOM是一个用JavaScript对象表示的DOM树,它可以在内存中快速地创建和修改,而不需要直接操作真实的DOMReact会根据组件的状态(state)和属性(props)来生成虚拟DOM,并与上一次的虚拟DOM进行比较,找出差异,然后将这些差异应用到真实的DOM上,从而更新用户界面。

公众号:Code程序人生,个人网站:https://creatorblog.cn

那么,React是如何知道什么时候需要重新渲染组件呢?

组件重新渲染的触发机制

一般来说,有以下四种情况会导致组件重新渲染:

组件状态(state)发生变化

当我们调用setState方法或者使用useState钩子(hook)来更新组件的状态时,React会自动重新渲染该组件及其子组件。

例如,下面的代码定义了一个简单的计数器组件,它使用useState钩子来管理计数值,并提供增加和减少的按钮。每次点击按钮时,都会调用setCount函数来更新计数值,从而触发组件的重新渲染。

import React, { useState } from "react";

function Counter() {
  // 使用useState钩子来创建一个状态变量count和一个更新函数setCount
  const [count, setCount] = useState(0);

  // 定义一个函数来增加计数值
  function handleIncrease() {
    // 调用setCount函数来更新计数值,传入一个函数作为参数,该函数接收上一次的计数值作为参数,并返回新的计数值
    setCount((prevCount) => prevCount + 1);
  }

  // 定义一个函数来减少计数值
  function handleDecrease() {
    // 调用setCount函数来更新计数值,传入一个函数作为参数,该函数接收上一次的计数值作为参数,并返回新的计数值
    setCount((prevCount) => prevCount - 1);
  }

  // 返回一个JSX元素,显示当前计数值,并提供增加和减少的按钮
  return (
    <div>
      <p>当前计数:{count}</p>
      <button onClick={handleIncrease}>增加</button>
      <button onClick={handleDecrease}>减少</button>
    </div>
  );
}

export default Counter;

组件属性(props)发生变化

当我们向组件传递新的属性值时,React会自动重新渲染该组件及其子组件。但是,这里有一个重要的细节:React并不是根据属性值本身是否变化来判断是否需要重新渲染,而是根据属性值的引用是否变化。

也就是说,如果我们传递了一个新创建的对象或数组作为属性值,即使它们的内容没有变化,也会触发重新渲染,因为它们的引用不同于之前的值。这也是为什么我们应该尽量避免在渲染函数中直接创建对象或数组作为属性值的原因。

例如,下面的代码定义了一个简单的列表组件,它接受一个数组作为属性值,并显示数组中的每个元素。在父组件中,我们每隔一秒就向列表组件传递一个新创建的数组,即使数组中的元素没有变化,也会导致列表组件重新渲染。

import React, { useState, useEffect } from "react";

// 一个简单的列表组件,接受一个数组作为属性值,并显示数组中的每个元素
function List({ items }) {
  console.log("List is rendering");
  return (
    <ul>
      {items.map((item) => (
        <li key={item}>{item}</li>
      ))}
    </ul>
  );
}

// 一个简单的父组件,管理一个数组,并定时向列表组件传递新创建的数组
function App() {
  const [items, setItems] = useState(["a", "b", "c"]);

  // 使用useEffect钩子来在组件挂载后定时更新数组
  useEffect(() => {
    // 定义一个定时器,在每隔一秒后调用setItems函数来更新数组
    const timer = setInterval(() => {
      // 调用setItems函数来更新数组,传入一个新创建的数组作为参数,该数组与之前的数组内容相同
      setItems(["a", "b", "c"]);
    }, 1000);

    // 返回一个清理函数,在组件卸载前取消定时器
    return () => {
      clearInterval(timer);
    };
  }, []);

  console.log("App is rendering");
  return (
    <div>
      <h1>React重新渲染示例</h1>
      {/* 向列表组件传递数组作为属性值 */}
      <List items={items} />
    </div>
  );
}

export default App;

组件所依赖的上下文(context)发生变化

当我们使用useContext钩子或者contextType属性来订阅一个上下文时,如果该上下文的值发生变化,React会自动重新渲染订阅了该上下文的所有组件。

例如,下面的代码定义了一个简单的主题组件,它使用createContext函数来创建一个主题上下文,并提供一个切换主题的按钮。在子组件中,我们使用useContext钩子来订阅主题上下文,并根据主题值来显示不同的颜色。每次点击按钮时,都会调用setTheme函数来更新主题值,从而触发子组件的重新渲染。

import React, { useState, createContext, useContext } from "react";

// 使用createContext函数来创建一个主题上下文,传入一个默认值作为参数
const ThemeContext = createContext("light");

// 一个简单的主题组件,使用useState钩子来管理主题值,并提供一个切换主题的按钮
function ThemeProvider({ children }) {
  // 使用useState钩子来创建一个状态变量theme和一个更新函数setTheme
  const [theme, setTheme] = useState("light");

  // 定义一个函数来切换主题
  function toggleTheme() {
    // 调用setTheme函数来更新主题值,传入一个函数作为参数,该函数接收上一次的主题值作为参数,并返回新的主题值
    setTheme((prevTheme) => (prevTheme === "light" ? "dark" : "light"));
  }

  // 返回一个JSX元素,使用ThemeContext.Provider组件来提供主题值,并显示切换主题的按钮和子组件
  return (
    <ThemeContext.Provider value={theme}>
      <button onClick={toggleTheme}>切换主题</button>
      {children}
    </ThemeContext.Provider>
  );
}

// 一个简单的子组件,使用useContext钩子来订阅主题上下文,并根据主题值来显示不同的颜色
function Child() {
  // 使用useContext钩子来获取主题上下文的值
  const theme = useContext(ThemeContext);

  // 返回一个JSX元素,根据主题值来设置样式,并显示当前主题
  return (
    <div style={{ color: theme === "light" ? "black" : "white" }}>
      当前主题:{theme}
    </div>
  );
}

// 一个简单的父组件,使用ThemeProvider组件来包裹子组件
function App() {
  return (
    <div>
      <h1>React重新渲染示例</h1>
      {/* 使用ThemeProvider组件来包裹子组件 */}
      <ThemeProvider>
        {/* 显示子组件 */}
        <Child />
      </ThemeProvider>
    </div>
  );
}

export default App;

组件所依赖的自定义钩子(custom hook)发生变化

当我们使用自定义钩子来封装一些逻辑或状态时,如果该钩子返回了一个新的值,React会自动重新渲染使用了该钩子的所有组件。

例如,下面的代码定义了一个简单的窗口大小钩子,它使用useStateuseEffect钩子来获取和更新窗口大小,并返回一个包含宽度和高度的对象。在组件中,我们使用这个自定义钩子来获取窗口大小,并显示在界面上。每次调整窗口大小时,都会触发自定义钩子返回一个新的对象,从而触发组件的重新渲染。

import React, { useState, useEffect } from "react";

// 定义一个自定义钩子,用于获取和更新窗口大小
function useWindowSize() {
  // 使用useState钩子来创建一个状态变量size和一个更新函数setSize
  const [size, setSize] = useState({
    // 初始化状态值为当前窗口的宽度和高度
    width: window.innerWidth,
    height: window.innerHeight,
  });

  // 使用useEffect钩子来在组件挂载后添加一个窗口大小变化的事件监听器,并在组件卸载前移除该监听器
  useEffect(() => {
    // 定义一个函数来处理窗口大小变化的事件
    function handleResize() {
      // 调用setSize函数来更新状态值,传入一个新创建的对象作为参数,该对象包含当前窗口的宽度和高度
      setSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    }

    // 添加一个窗口大小变化的事件监听器,传入handleResize函数作为参数
    window.addEventListener("resize", handleResize);

    // 返回一个清理函数,在组件卸载前移除事件监听器
    return () => {
      window.removeEventListener("resize", handleResize);
    };
  }, []);

  // 返回状态值
  return size;
}

// 一个简单的组件,使用useWindowSize钩子来获取窗口大小,并显示在界面上
function App() {
  // 使用useWindowSize钩子来获取窗口大小
  const size = useWindowSize();

  // 返回一个JSX元素,显示当前窗口的宽度和高度
  return (
    <div>
      <h1>React重新渲染示例</h1>
      <p>当前窗口大小:{size.width} x {size.height}</p>
    </div>
  );
}

export default App;

如何避免不必要的重新渲染

以上四种情况都是必要的重新渲染,因为它们反映了组件内部或外部的数据变化,从而保证了用户界面与数据保持一致。

但是,在一些情况下,我们可能会遇到不必要的重新渲染,即组件没有任何数据变化,但仍然被重新渲染了。这可能会导致性能问题,特别是当组件很复杂或者很频繁地被重新渲染时。那么,如何避免不必要的重新渲染呢?有以下几种常用的优化策略:

React.memo

使用React.memo高阶组件来包裹函数式组件。这样可以让React在渲染组件之前先对比一下属性值是否有变化,如果没有变化,则跳过渲染。这可以避免因为父组件重新渲染而导致子组件也跟着重新渲染的情况。

例如,下面的代码定义了一个简单的计数器组件,它接受一个数字作为属性值,并显示该数字。在父组件中,我们使用useState钩子来管理一个数字,并提供一个增加的按钮。每次点击按钮时,都会调用setNumber函数来更新数字,从而触发父组件的重新渲染。

如果我们不使用React.memo来包裹计数器组件,则每次点击按钮时,计数器组件也会被重新渲染,即使它的属性值没有变化。如果我们使用React.memo来包裹计数器组件,则只有当它的属性值变化时,才会触发它的重新渲染。

import React, { useState } from "react";

// 一个简单的计数器组件,接受一个数字作为属性值,并显示该数字
function Counter({ number }) {
  console.log("Counter is rendering");
  return <p>当前数字:{number}</p>;
}

// 使用React.memo包裹计数器组件,使其只在属性值变化时才重新渲染
const MemoizedCounter = React.memo(Counter);

// 一个简单的父组件,使用useState钩子来管理一个数字,并提供一个增加的按钮
function App() {
  // 使用useState钩子来创建一个状态变量number和一个更新函数setNumber
  const [number, setNumber] = useState(0);

  // 定义一个函数来增加数字
  function handleIncrease() {
    // 调用setNumber函数来更新数字,传入一个函数作为参数,该函数接收上一次的数字作为参数,并返回新的数字
    setNumber((prevNumber) => prevNumber + 1);
  }

  console.log("App is rendering");
  return (
    <div>
      <h1>React重新渲染示例</h1>
      <button onClick={handleIncrease}>增加</button>
      {/* 向计数器组件传递数字作为属性值 */}
      <MemoizedCounter number={number} />
    </div>
  );
}

export default App;

useMemo

使用useMemo钩子来缓存计算结果。这样可以让我们只在依赖项发生变化时才重新计算结果,而不是每次渲染都计算。这可以避免因为计算开销大而导致渲染时间过长的情况。

例如,下面的代码定义了一个简单的斐波那契数列组件,它接受一个数字作为属性值,并显示该数字对应的斐波那契数。在父组件中,我们使用useState钩子来管理一个数字,并提供一个增加和减少的按钮。每次点击按钮时,都会调用setNumber函数来更新数字,从而触发父组件和子组件的重新渲染。

如果我们不使用useMemo钩子来缓存斐波那契数的计算结果,则每次重新渲染都会重新执行斐波那契数的递归函数,这会消耗很多时间和资源。如果我们使用useMemo钩子来缓存斐波那契数的计算结果,则只有当依赖项变化时才会重新执行斐波那契数的递归函数。

import React, { useState, useMemo } from "react";

// 定义一个函数来计算斐波那契数,使用递归的方式
function fibonacci(n) {
  // 如果n小于等于1,则返回n
  if (n <= 1) {
    return n;
  }
  // 否则,返回前两项的和
  return fibonacci(n - 1) + fibonacci(n - 2);
}

// 一个简单的斐波那契数列组件,接受一个数字作为属性值,并显示该数字对应的斐波那契数
function Fibonacci({ number }) {
  // 使用useMemo钩子来缓存斐波那契数的计算结果,传入一个函数作为参数,该函数返回斐波那契数的值,以及一个数组作为依赖项,该数组包含了影响计算结果的变量
  const result = useMemo(() => {
    // 调用fibonacci函数来计算斐波那契数的值
    return fibonacci(number);
  }, [number]); // 依赖项是number,只有当number变化时才会重新计算结果

  console.log("Fibonacci is rendering");
  return <p>{number}项斐波那契数是:{result}</p>;
}

// 一个简单的父组件,使用useState钩子来管理一个数字,并提供一个增加和减少的按钮
function App() {
  // 使用useState钩子来创建一个状态变量number和一个更新函数setNumber
  const [number, setNumber] = useState(0);

  // 定义一个函数来增加数字
  function handleIncrease() {
    // 调用setNumber函数来更新数字,传入一个函数作为参数,该函数接收上一次的数字作为参数,并返回新的数字
    setNumber((prevNumber) => prevNumber + 1);
  }

  // 定义一个函数来减少数字
  function handleDecrease() {
    // 调用setNumber函数来更新数字,传入一个函数作为参数,该函数接收上一次的数字作为参数,并返回新的数字
    setNumber((prevNumber) => prevNumber - 1);
  }

  console.log("App is rendering");
  return (
    <div>
      <h1>React重新渲染示例</h1>
      <button onClick={handleIncrease}>增加</button>
      <button onClick={handleDecrease}>减少</button>
      {/* 向斐波那契数列组件传递数字作为属性值 */}
      <Fibonacci number={number} />
    </div>
  );
}

export default App;

useCallback

使用useCallback钩子来缓存函数。这样可以让我们只在依赖项发生变化时才重新创建函数,而不是每次渲染都创建。这可以避免因为传递了新的函数作为属性值而导致子组件重新渲染的情况。

例如,下面的代码定义了一个简单的计数器组件,它接受两个函数作为属性值,并提供增加和减少的按钮。在父组件中,我们使用useState钩子来管理一个数字,并定义两个函数来修改数字。每次点击按钮时,都会调用相应的函数来更新数字,从而触发父组件和子组件的重新渲染。

如果我们不使用useCallback钩子来缓存这两个函数,则每次重新渲染都会创建新的函数,并传递给子组件,从而触发子组件的重新渲染。如果我们使用useCallback钩子来缓存这两个函数,则只有当依赖项变化时才会重新创建函数,并传递给子组件。

import React, { useState, useCallback } from "react";

// 一个简单的计数器组件,接受两个函数作为属性值,并提供增加和减少的按钮
function Counter({ onIncrease, onDecrease }) {
  console.log("Counter is rendering");
  return (
    <div>
      <button onClick={onIncrease}>增加</button>
      <button onClick={onDecrease}>减少</button>
    </div>
  );
}

// 一个简单的父组件,使用useState钩子来管理一个数字,并定义两个函数来修改数字
function App() {
  // 使用useState钩子来创建一个状态变量number和一个更新函数setNumber
  const [number, setNumber] = useState(0);

  // 使用useCallback钩子来缓存增加数字的函数,传入一个函数作为参数,该函数返回增加数字的操作,以及一个数组作为依赖项,该数组包含了影响函数结果的变量
  const handleIncrease = useCallback(() => {
    // 调用setNumber函数来更新数字,传入一个函数作为参数,该函数接收上一次的数字作为参数,并返回新的数字
    setNumber((prevNumber) => prevNumber + 1);
  }, []); // 依赖项是空数组,表示该函数不依赖于任何外部变量,只在组件挂载时创建一次

  // 使用useCallback钩子来缓存减少数字的函数,传入一个函数作为参数,该函数返回减少数字的操作,以及一个数组作为依赖项,该数组包含了影响函数结果的变量
  const handleDecrease = useCallback(() => {
    // 调用setNumber函数来更新数字,传入一个函数作为参数,该函数接收上一次的数字作为参数,并返回新的数字
    setNumber((prevNumber) => prevNumber - 1);
  }, []); // 依赖项是空数组,表示该函数不依赖于任何外部变量,只在组件挂载时创建一次

  console.log("App is rendering");
  return (
    <div>
      <h1>React重新渲染示例</h1>
      <p>当前数字:{number}</p>
      {/* 向计数器组件传递缓存后的函数作为属性值 */}
      <Counter onIncrease={handleIncrease} onDecrease={handleDecrease} />
    </div>
  );
}

export default App;

React.PureComponent/shouldComponentUpdate

使用React.PureComponent或者shouldComponentUpdate方法来优化类组件。这样可以让React在渲染组件之前先对比一下状态和属性值是否有变化,如果没有变化,则跳过渲染。这与React.memo类似,但是适用于类组件。

例如,下面的代码定义了一个简单的计数器组件,它继承自React.PureComponent类,并使用this.statethis.setState方法来管理计数值,并提供增加和减少的按钮。在父组件中,我们使用useState钩子来管理一个数字,并提供一个增加的按钮。

每次点击按钮时,都会调用setNumber函数来更新数字,从而触发父组件的重新渲染。如果我们不继承自React.PureComponent类,则每次点击按钮时,计数器组件也会被重新渲染,即使它的状态和属性值没有变化。如果我们继承自React.PureComponent类,则只有当它的状态或属性值变化时,才会触发它的重新渲染。

import React, { useState } from "react";

// 一个简单的计数器组件,继承自React.PureComponent类,并使用this.state和this.setState方法来管理计数值,并提供增加和减少的按钮
class Counter extends React.PureComponent {
  // 定义一个构造函数,接受一个属性对象作为参数,并调用父类的构造函数
  constructor(props) {
    super(props);

    // 初始化状态对象,包含一个计数值
    this.state = {
      count: 0,
    };
  }

  // 定义一个方法来增加计数值
  handleIncrease = () => {
    // 调用this.setState方法来更新状态对象,传入一个函数作为参数,该函数接收上一次的状态对象作为参数,并返回新的状态对象
    this.setState((prevState) => ({
      // 返回新的状态对象,将计数值加一
      count: prevState.count + 1,
    }));
  };

  // 定义一个方法来减少计数值
  handleDecrease = () => {
    // 调用this.setState方法来更新状态对象,传入一个函数作为参数,该函数接收上一次的状态对象作为参数,并返回新的状态对象
    this.setState((prevState) => ({
      // 返回新的状态对象,将计数值减一
      count: prevState.count - 1,
    }));
  };

  // 定义一个渲染方法,返回一个JSX元素,显示当前计数值,并提供增加和减少的按钮
  render() {
    console.log("Counter is rendering");
    return (
      <div>
        <p>当前计数:{this.state.count}</p>
        <button onClick={this.handleIncrease}>增加</button>
        <button onClick={this.handleDecrease}>减少</button>
      </div>
    );
  }
}

// 一个简单的父组件,使用useState钩子来管理一个数字,并提供一个增加的按钮
function App() {
  // 使用useState钩子来创建一个状态变量number和一个更新函数setNumber
  const [number, setNumber] = useState(0);

  // 定义一个函数来增加数字
  function handleIncrease() {
    // 调用setNumber函数来更新数字,传入一个函数作为参数,该函数接收上一次的数字作为参数,并返回新的数字
    setNumber((prevNumber) => prevNumber + 1);
  }

  console.log("App is rendering");
  return (
    <div>
      <h1>React重新渲染示例</h1>
      <button onClick={handleIncrease}>增加</button>
      {/* 向计数器组件传递数字作为属性值 */}
      <Counter number={number} />
    </div>
  );
}

export default App;

key

使用key属性来优化列表渲染。这样可以让React在渲染列表时能够识别出每个列表项的唯一标识,从而避免不必要的创建和销毁。这可以提高列表渲染的性能和稳定性。

例如,下面的代码定义了一个简单的待办事项列表组件,它接受一个数组作为属性值,并显示数组中的每个元素。在父组件中,我们使用useState钩子来管理一个数组,并提供一个添加和删除的按钮。每次点击按钮时,都会调用相应的函数来更新数组,从而触发父组件和子组件的重新渲染。

如果我们不使用key属性来给每个列表项分配一个唯一标识,则每次重新渲染都会导致所有的列表项被重新创建和销毁,这会浪费很多时间和资源。如果我们使用key属性来给每个列表项分配一个唯一标识,则只有当列表项增加或减少时才会触发创建和销毁,而当列表项顺序变化时则只会触发移动,这会节省很多时间和资源。

import React, { useState } from "react";

// 一个简单的待办事项列表组件,接受一个数组作为属性值,并显示数组中的每个元素
function TodoList({ items }) {
  console.log("TodoList is rendering");
  return (
    <ul>
      {items.map((item) => (
        // 使用key属性来给每个列表项分配一个唯一标识,这里我们使用item.id作为标识
        <li key={item.id}>{item.text}</li>
      ))}
    </ul>
  );
}

// 一个简单的父组件,使用useState钩子来管理一个数组,并提供一个添加和删除的按钮
function App() {
  // 使用useState钩子来创建一个状态变量items和一个更新函数setItems
  const [items, setItems] = useState([
    // 初始化状态值为一个包含三个对象的数组,每个对象包含一个id和一个text
    { id: 1, text: "学习React" },
    { id: 2, text: "写博客" },
    { id: 3, text: "做运动" },
  ]);

  // 定义一个函数来添加待办事项
  function handleAdd() {
    // 调用setItems函数来更新状态值,传入一个函数作为参数,该函数接收上一次的状态值作为参数,并返回新的状态值
    setItems((prevItems) => [
      // 返回新的状态值,将上一次的状态值复制一份,并在末尾添加一个新的对象,该对象包含一个随机生成的id和一个固定的text
      ...prevItems,
      { id: Math.random(), text: "新待办事项" },
    ]);
  }

  // 定义一个函数来删除待办事项
  function handleDelete() {
    // 调用setItems函数来更新状态值,传入一个函数作为参数,该函数接收上一次的状态值作为参数,并返回新的状态值
    setItems((prevItems) => [
      // 返回新的状态值,将上一次的状态值复制一份,并删除第一个元素
      ...prevItems.slice(1),
    ]);
  }

  console.log("App is rendering");
  return (
    <div>
      <h1>React重新渲染示例</h1>
      <button onClick={handleAdd}>添加</button>
      <button onClick={handleDelete}>删除</button>
      {/* 向待办事项列表组件传递数组作为属性值 */}
      <TodoList items={items} />
    </div>
  );
}

export default App;

总结

React是一个用于构建用户界面的JavaScript库,它使用虚拟DOM来高效地渲染组件。组件的状态(state)、属性(props)、上下文(context)和自定义钩子(custom hook)的变化会触发重新渲染。有时,我们需要避免不必要的重新渲染,以提高性能和稳定性。我们可以使用以下几种优化策略:

  • 使用React.memouseMemouseCallback来缓存函数式组件、计算结果和函数,使其只在依赖项变化时才重新渲染或创建。
  • 使用React.PureComponent或者shouldComponentUpdate方法来优化类组件,使其只在状态或属性值变化时才重新渲染。
  • 使用key属性来优化列表渲染,使React能够识别每个列表项的唯一标识,从而避免不必要的创建和销毁。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

React重新渲染的触发机制及其优化策略 的相关文章

  • 在文件之间共享变量(没有全局变量)

    据我了解 使用创建的变量let在 Javascript 中不能是全局的 我thought这意味着该变量仅存在于该特定文件中 然而 当我做一个简单 人为的例子时 A js let a 5 B js console log a 索引 html
  • Javascript 单元测试 - DOM 操作

    我对 Javacript 单元测试很陌生 有件事一直困扰着我 在测试 javascript 时 我们经常需要进行 DOM 操作 看起来我正在对控制器 组件中的方法 函数进行单元测试 但我仍然需要依赖模板中的 HTML 元素 一旦 id 或在
  • 向回调函数添加附加参数

    我正在 Node js 中构建一个系统 该系统应该查找文件夹数组中的所有文件 统计它们 然后使用该信息执行一些其他工作 我使用 fs readdir 从每个文件夹同步获取所有文件 我的代码如下所示 for i 0 max paths len
  • 直接加载页面到锚标记

    当我加载 URL 中带有哈希标记的页面时 页面会加载 然后跳转到锚标记 有没有什么方法可以防止这种 跳转 要么直接将页面加载到锚标记 要么至少使滚动平滑 我在 Chrome 和 Firefox 中看到这个问题 但在 IE 中没有 如果你仍然
  • 无法通过 phantomjs 网络服务器传送图像文件

    我正在尝试让 phantomjs 网络服务器为我工作 我想提供 2 个文件 html 文件和 png 图像文件 html 文件服务良好并在浏览器中正确呈现 但 png 文件不是 这是服务器的代码 var fs require fs func
  • Angular:将数据从工厂 ajax 调用传递回我的控制器

    我一直在使用 Angular 并且已经从使用本地数据 似乎工作正常 转向尝试通过工厂中的 ajax 调用来填充我的视图 这是代码 div h2 Get data using a Factory h2 div div div
  • 分层边缘捆绑:添加父组标签

    我对 HTML 和 JavaScript 还很陌生 我面临着著名的分层边缘捆绑可用here https bl ocks org mbostock 7607999 由 D3 js 库生成 My goal is to add a semi ci
  • 将颜色渐变应用于网格上的材质 - Three.js

    我有一个 STL 文件加载到我的场景中 并将单一颜色应用于 phong 材质 我想要一种方法 将两种颜色应用于该网格物体的材质 并在 Z 轴上应用渐变效果 如下例所示 渐变花瓶 https i stack imgur com Ty9gq j
  • 如何重载材质 Switch 组件 css

    我正在尝试重载 MuiSwitch track 类开关 但它不起作用 基本上我想重载特定开关 我尝试使用 global MuiSwitch track backgroundColor d80c0a 但它使所有开关超载 有什么办法可以对单个开
  • Javascript 子字符串方法帮助

    长话短说 我正在开发一个 Web 应用程序并在其中使用 AJAX 我试图禁用点击时链接的默认操作 将哈希值附加到链接 然后从网址中删除 我遇到的问题是 虽然哈希值被相应地附加 但子字符串方法并没有提取 而是提取了它后面的字母 这是我的代码
  • XMLHttpRequest 无法加载 ZScaler 的问题

    我在 EC2 实例中托管了一个网站 并使用以下命令访问该页面http ec2 网址 该页面向同一实例上托管的另一个 Web 应用程序发出 ajax 请求 如果我访问通过 ZScaler 代理的页面 我会得到XMLHttpRequest ca
  • 如何通过 JavaScript 函数在 HTML5 画布上绘制多边形

    我希望用户能够单击画布上的某个位置 多边形就会出现在上面 div class rounded div
  • `[$injector:nomod] 模块“google-maps”不可用`

    我正在使用 angular google maps 在角度应用程序中处理谷歌地图 为此 我必须添加angular google maps js到项目 如果我按以下方式添加脚本 该页面可以正常工作 不会出现任何错误 但如果我使用本地副本 它将
  • ASP.Net Web 应用程序 Jquery Photoviewer 和 Ajaxical 更新

    有一个错误我的网站 http new mnarfezhom com 请进入右数第三个菜单 有些图像只能通过 jquery photoviewer 显示 onlclick 这很好用 现在 当我单击页面底部的 Ajaxical 更新按钮时 问题
  • 我想从 Cakefile 运行 d3

    我想从命令行执行一些 d3 代码 最初我只是尝试了类似的方法 task data Build some data with d3 gt d3 require lib d3 v2 console log d3 version d3 versi
  • 数据与线的日期和时间转换

    我使用 D3 V5 创建了此图表 另外 我已在小提琴上附加了示例数据 您可以点击此处查看 https plnkr co edit pINxcS9yt9AuJmSk02Fs p preview 我已经包括了tick函数代码块 它在向左滑动的路
  • 有没有办法向 JavaScript 对象添加元数据?

    我想将元数据的键值对添加到任意 JavaScript 对象 此元数据不应影响不知道元数据的代码 这意味着例如 JSON stringify obj JSON stringify obj WithMetaData key value 元数据感
  • 使用两个键执行自动完成 - Material UI with React

    当使用两个值之一搜索时 我试图自动完成输入 title and year 但是 它仅在我搜索时才有效title 当我搜索时year 它不显示任何选项 示例代码 export default function ComboBox return
  • 在 Firefox 中单击桌面通知时如何将焦点移至选项卡?

    我正在一个网站中实现桌面通知 该网站会在新消息到达时显示通知 我希望当用户单击通知时 打开网站的浏览器选项卡能够获得焦点 我可以使用以下代码在 Chrome 中实现此功能 var n new Notification Title body
  • jQuery mobile 在 Opera Mini 浏览器中失败。如何获得错误输出?

    I have a jQuery Mobile http en wikipedia org wiki JQuery Mobile website that works great on normal browsers but it fails

随机推荐

  • Windows Ubuntu 双系统安装教程

    基本步骤 1 确定自己的硬盘分区 并分区 以我120G固态硬盘 500G机械硬盘的笔记本电脑为例 不打游戏的码农 win用于生活 ubuntu用于工作 C盘 80G固态硬盘 设为ntfs文件格式 用来放Windows系统及相关软件 分区 大
  • Vue中mapbox的使用

    Vue中mapbox的使用 1 首先下载包文件 cnpm i mapbox gl S 2 导入包文件 main js中导入 import mapBoxGl from mapbox gl Vue prototype mapboxgl mapB
  • jwt 私钥_基于JWT的token弱密钥爆破

    JSON Web Token JWT 是目前最流行的跨域身份验证解决方案 直接根据token取出保存的用户信息 以及对token可用性校验 大大简化单点登录 JWT header payload signature 以 相隔 例 eyJhb
  • SpringBoot3基础:最简项目示例

    说明 本文建立一个最基本的SpringBoot3项目 依赖项仅包含 spring web SpringMVC 备注 SpringBoot3需要JDK17支持 配置方法参考 SpringBoot3项目中配置JDK17 项目结构图示 POM
  • 现在学UI设计有前途吗?UI设计收入大概多少

    随着互联网的高速发展以及大量的人奔涌进入UI设计行业 我们发现想要通过UI实现高薪就业变得不再容易 这让很多人担忧 现在学UI设计还有前途吗 千锋郑州UI设计老师从市场需求 就业薪资以及职业发展方向三个角度分析后可以负责的告诉你有前途 UI
  • docke的基础入门

    docker基础入门操作 一 如何安装docker 一 如何安装docker 安装docker命令通过一下命令顺序执行 即可进行安装 校验操作系统内核版本 要求是3 10以上的版本 1 安装一些必要的系统工具 其中yum utils包含yu
  • 由于找不到vcomp140.dll无法继续执行此代码?该怎么修复呢?

    在使用计算机过程中 我们有时会遇到缺少vcomp140 dll文件的问题 这可能导致某些应用程序无法正常运行 遇到了缺少vcomp140 dll文件的问题 这给我的正常工作和娱乐带来了一些困扰 经过一番努力 我成功修复了这个问题 并对此总结
  • shell中括号的特殊用法 linux if多条件判断

    shell中括号的特殊用法 linux if多条件判断 一 bash 单双括号 基本要素 两个符号左右都要有空格分隔 内部操作符与操作变量之间要有空格 如 a b 字符串比较中 gt lt 需要写成 gt lt 进行转义 中字符串或者 变量
  • Cause: org.jetbrains.plugins.gradle.tooling.util.ModuleComponentIdentifierImpl.getM的原因及解决办法

    一 原因 从别人那里拿来的gradle项目 然后自己用idea跑的时候报错 Cause org jetbrains plugins gradle tooling util ModuleComponentIdentifierImpl getM
  • linux 解锁用户被锁

    一般我们在开发时部署好了环境 有时候用xshell 登录服务器时我们经常会忘记用户的登录密码 我们经常会遇到用户被锁定 首先 用root 用户查看 查看被锁用户的错误登录次数 pam tally2 u tom tom 为用户 pam tal
  • qt集成cef QWidget

    编译libcef dll wrapper 假设你已经编译出了libcef dll wrapper lib Debug和Release版本 并且对应版本的程序集类型分别是 MDd和MD qt的运行时库是MDd类型的 因此cef3编译的时候也应
  • hive 异常之 MetaException

    直接启动hive后 hive gt show databases FAILED SemanticException org apache hadoop hive ql metadata HiveException java lang Run
  • vue3中对本地存储的数据多次修改并实时页面显示

    背景 项目中遇到切换用户时 对App页面的信息进行实时显示 登录时存储一次 切换时再次存储 解决办法 1 在每次存储的同时存储到pinia中 可解决实时显示问题 import useCommonStore from pinia ls set
  • 软件测试中的43个功能测试点总结

    功能测试就是对产品的各功能进行验证 根据功能测试用例 逐项测试 检查产品是否达到用户要求的功能 针对web系统的常用测试方法如下 1 页面链接检查 每一个链接是否都有对应的页面 并且页面之间切换正确 可以使用一些工具 如LinkBotPro
  • C++学习(四八七)android studio println的输出位置

    程序中调用如下输出 System out println haha1 调试情况下 在Run和LogCat下均看不到输出 运行情况下 在Run下能看到输出 建议如下 可在LogCat中看到信息 android util Log常用的方法有以下
  • 蓝牙之十三-HFPclient JNI层

    JNI到app JAVA
  • 开营

    2021未来杯区块链应用创新大赛已于9月24日正式启动 本届大赛是由中国信息协会主办 中国信息协会教育分会 艾肯文化传媒 北京 有限公司 中软国际教育科技集团 以太坊行星承办 北京大学研发实验服务基地 iCAN国际联盟 STEERTECH科
  • echarts修改折线图样式,总结踩坑以及常用

    以折线图为例 最终呈现的效果是这样的 在最外层可以设置 距离外层box的距离 myChart setOption grid 距离外层box左右位置 x 30 左 y 45 上 x2 45 右 y2 40 下 borderWidth 1 在x
  • 【WSN无线传感器网络恶意节点】使用 MATLAB 进行无线传感器网络部署研究

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码实现 1 概述 在无线传感器网络部署方面 您计划在一个 1
  • React重新渲染的触发机制及其优化策略

    React是一个用于构建用户界面的JavaScript库 它的核心特点之一是使用虚拟DOM Virtual DOM 来实现高效的组件渲染 那组件重新渲染的机制是如何呢 基于这些机制 如果进行优化呢 虚拟DOM是一个用JavaScript对象