百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT知识 > 正文

最强echarts封装(优化依赖自动渲染清除大小自适应,主题切换)

liuian 2025-01-31 14:02 45 浏览

前言

我们在书写echarts组件的时候,往往会发现:

其打包的chunk包是全量的,比较大。

调用api麻烦,要注意dom的渲染时机,资源清除,大小自适应。

不支持css变量,无法动态换肤的。

本文就围绕以上几点进行提供一个解决方案。

技术栈

Vue/React Echarts TS 本文以Vue为例,文末会贴上React实现方案

github仓库地址: github.com/Freedom-FJ/…

依赖引入

首先为了解决echarts的全量引入问题,我们需要单独书写一个echarts依赖引入文件。

  • 引入部分的 echarts/componentscharts 等,把我们项目中用到的echarts部分依赖引入进来
  • echarts.use 挂载到我们的echarts实例上。
  • 书写 echarts.draw 语法糖,可以一键对dom节点进行初始化,清除并绘制新的echarts对象。

utils/echarts/index.ts

ts复制代码/*
 * @Author: mjh
 * @Date: 2023-08-11 12:16:33
 * @LastEditors: mjh
 * @LastEditTime: 2023-08-15 10:20:14
 * @Description:
 */
import * as echarts from 'echarts/core'
import { GraphicComponent, GridComponent, LegendComponent, PolarComponent, TitleComponent, TooltipComponent } from 'echarts/components'
import { BarChart, BoxplotChart, LineChart, PieChart, RadarChart } from 'echarts/charts'
import { UniversalTransition } from 'echarts/features'
import { CanvasRenderer } from 'echarts/renderers'

echarts.use([
    GraphicComponent,
    GridComponent,
    TooltipComponent,
    LegendComponent,
    TitleComponent,
    LineChart,
    BarChart,
    PieChart,
    BoxplotChart,
    CanvasRenderer,
    UniversalTransition,
    RadarChart,
    PolarComponent,
])
// import * as echarts from 'echarts'

// 初始化语法糖
const draw = (dom: HTMLElement, option: Record<string, any>) => {
    const chart = echarts.init(dom)
    chart.clear()
    chart.setOption(option)
    return chart
}

export default {
    ...echarts,
    draw
} as any

接下来我们要书写一个 echarts 组件,只需要我们传入option 就可以自动的绘制echarts节点。

书写组件

简单组件

我们先写一个简单的vue显示echarts的组件,我们需要在初始化的时候获取到dom节点,并且监听option如参,动态的更新渲染echarts实例。 但是不要忘了在组件销毁的时候清除echarts实例,防止占用内存。

vue复制代码<template>
    <div ref="domBox" :style="{ width, height }">
        <div ref="domRef" :style="{ width, height }" />
    </div>
</template>

<script lang="ts" setup>
import { watch, ref, onMounted, onUnmounted } from 'vue'
import type { ECharts } from 'echarts'
import echarts from './index'
const props = defineProps({
    width: {
        type: String,
        default: '100%',
    },
    height: {
        type: String,
        default: '100%',
    },
    options: {
        type: Object,
        default: null,
    },
})

const domRef = ref(null)
const domBox = ref(null)
let chartObj: null | ECharts = null


onMounted(() => {
    if (!domRef.value) return
    init()
    if (props.options)
        drawOption()
})

onUnmounted(() => {
    if (chartObj) {
        chartObj.dispose()
        chartObj = null
    }
})

watch(() => props.options, () => drawOption())

// 初始化
const init = () => {
    chartObj = (echarts.init(domRef.value) as any)
}

const drawOption = () => {
    if(!chartObj) return
    chartObj.setOption(props.options)
}
</script>

监听dom更新

不要忘了我们在绘制echarts实例的时候,如果我们已经绘制完了,但是我们的外部盒子尺寸发生变化了怎么办,这个时候我们就要监听我们的外部盒子的尺寸变化来动态的 resize 我们的echarts实例。

MutationObserver 接口提供了监视对 DOM 树所做更改的能力。创建并返回一个新的 MutationObserver 它会在指定的 DOM 发生变化时被调用。 其的 observe() 方法配置了 MutationObserver 对象的回调方法以开始接收与给定选项匹配的 DOM 变化的通知。 根据配置,观察者会观察 DOM 树中的单个 Node,也可能会观察被指定节点的部分或者所有的子孙节点。 要停止 MutationObserver(以便不再触发它的回调方法),需要调用 MutationObserver.disconnect() 方法。

语法

js复制代码var mutationObserver = new MutationObserver(callback);
mutationObserver.observe(target[, options])
  • callback
  • 一个回调函数,每当被指定的节点或子树以及配置项有 DOM 变动时会被调用。回调函数拥有两个参数:一个是描述所有被触发改动的 MutationRecord 对象数组,另一个是调用该函数的 MutationObserver 对象。

对于其option下面我们需要用到以下几个语法

  • subtree 可选
  • 当为 true 时,将会监听以 target 为根节点的整个子树。包括子树中所有节点的属性,而不仅仅是针对 target。默认值为 false
  • childList 可选
  • 当为 true 时,监听 target 节点中发生的节点的新增与删除(同时,如果 subtreetrue,会针对整个子树生效)。默认值为 false
  • attributes 可选
  • 当为 true 时观察所有监听的节点属性值的变化。默认值为 true,当声明了 attributeFilterattributeOldValue,默认值则为 false
  • characterData 可选
  • 当为 true 时,监听声明的 target 节点上所有字符的变化。默认值为 true,如果声明了 characterDataOldValue,默认值则为 false

获取实例监听变化

js复制代码const observer = new MutationObserver((mutationsList) => {
    // 循环寻找我们的echarts dom实例,发现更新的内容包含则调用 resize 方法更新echarts的尺寸
    for (const mutation of mutationsList)
        if (mutation.target === echartDomBox.value) chartObj && chartObj.resize()
})

observer.observe(domBox.value, {
    attributes: true,
    childList: false,
    characterData: true,
    subtree: true
})

我们将其应用到组建内,同时为了增加交互的舒适我们还可以利用echarts api 的 showLoading 加上loading的动画效果,(也可以使用 hideLoading 方法隐藏效果),为我们组件在未渲染实例时提升交互体验。

vue复制代码<template>
    <div ref="domBox" :style="{ width, height }">
        <div ref="domRef" :style="{ width, height }" />
    </div>
</template>

<script lang="ts" setup>
import { watch, ref, onMounted, onUnmounted, nextTick } from 'vue'
import type { ECharts } from 'echarts'
import echarts from './index'

const props = defineProps({
    width: {
        type: String,
        default: '100%',
    },
    height: {
        type: String,
        default: '100%',
    },
    options: {
        type: Object,
        default: null,
    },
})

const domRef = ref(null)
const domBox = ref(null)
let chartObj: null | ECharts = null
let observer: null | MutationObserver = null // dom 监听

onMounted(() => {
    if (!domRef.value) return
    init()
    !props.options && chartObj.showLoading({
        text: '',
        color: '#409eff',
        textColor: '#000',
        maskColor: 'rgba(255, 255, 255, .95)',
        zlevel: 0,
        lineWidth: 2,
    })
        
    if (props.options)
        drawOption()

    observer = new MutationObserver((mutationsList) => {
        for (const mutation of mutationsList)
            if (mutation.target === domBox.value) chartObj && chartObj.resize()
    })
    // 注意: 要放在nextTick内,,因为初始化时我们已经进行了一次option的更新操作
    nextTick(() => {
        domBox.value && (observer as MutationObserver).observe(domBox.value, {
            attributes: true,
            childList: false,
            characterData: true,
            subtree: true
        })
    })

    setTimeout(() => {
        chartObj && chartObj.resize()
    }, 1000)
})

onUnmounted(() => {
    if (chartObj) {
        chartObj.dispose()
        chartObj = null
    }
    // 注意销毁监听器
    observer && observer.disconnect()
})

watch(() => props.options, () => drawOption())

// 初始化
const init = () => {
    chartObj = (echarts.init(domRef.value) as any)
}

const drawOption = () => {
    if(!chartObj) return
    chartObj.hideLoading()
    chartObj.setOption(props.options)
}
</script>

皮肤切换

主题切换现在比较主流的而且适配最好的是CSS变量的方案,也就是所有的颜色都采用css变量进行替换。我们只需要引入新的样式表,不需要额外的js代码,浏览器会自动更新CSSOM树,重绘所有dom的颜色,实现主体切换。

但是echarts不支持皮肤切换,因为其颜色是通过option传入的,使用canvas渲染实例,而且其传入颜色变量的字符串是无法识别的,必须直接传入颜色值,不支持css变量动态渲染,但是我们可以帮他做这个操作。

我们在echarts 传入的opiton的所有颜色处,做一层代理,我们传入所有的颜色都是变量的字符串例如:'var(--dv-color-1)' 在渲染的时候通过中间函数,将所有的颜色变量转化成真正的颜色值例如: #fff 那么只需要监听主题的切换然后重新在将传入的option进行更新颜色值再更新echarts即可。

好了思路有了,那我们开干!。

切换颜色值

首先书写一个 replaceVarStrings 中间函数用于将option内的所有颜色变量字符串都转化为真正的颜色值,匹配 var() 字符串并将其中间的颜色提取出来。 当然我们需要用到宏api getComputedStyle 实时动态计算获取我们的dom实例的样式属性,其返回值的 getPropertyValue 方法传入变量名称字符串就会返回实时的变量颜色值。

但是getComputedStyle会导致浏览器的重排,都为求一个“即时性”和“准确性”。

ts复制代码/**
 * echarts样式
 */
export const useThemeValue = (styleVariables: string) => {
    return getComputedStyle(document.documentElement).getPropertyValue(styleVariables)
}

export function replaceVarStrings(obj: Record<string, any>) {
    const newObj: Record<string, any> = Array.isArray(obj) ? [] : {}
    for (const key in obj) {
        if (typeof obj[key] === 'object') {
            newObj[key] = replaceVarStrings(obj[key]) // 递归处理子对象
        }
        else if (typeof obj[key] === 'string' && obj[key].startsWith('var(') && obj[key].endsWith(')')) {
            const varContent = obj[key].slice(4, -1) // 提取括号内的内容
            newObj[key] = useThemeValue(varContent) // 替换为括号内的内容
        }
        else {
            newObj[key] = obj[key] // 其他情况直接复制值
        }
    }

    return newObj
}

监听主题切换

以我们的element-plus 组件库主题切换为例,其切换为 dark 模式是在html 的标签上增加一个 dark的class类

html复制代码<!-- 正常 模式 -->
<html> </html>

<!-- dark 模式 -->
<html class="dark"> </html>

通过一套 dark 的变量样式覆盖原来的html下的样式

css复制代码html {
    --dv-color-background-base: #000b1a;
    --dv-color-background-overlay: #000b1a;
    --dv-color-background-page: #000b1a;
}

/* dark 模式 */
html .dark {
    --dv-color-background-base: #000b1a;
    --dv-color-background-overlay: #000b1a;
    --dv-color-background-page: #000b1a;
}

剩下只需要监听html dom节点的class列表即可。 但是监听 div span document这种很常见,可是怎么监听 html啊? 其实html 标签也是一个标签,你可以将它当作一个dom盒子,只需要像获取div一样 直接 document.querySelector('html') 即可获取到他的对象了。 监听class类还是用上文讲到的 MutationObserver ,只是不同的是 observer 方法的入参属性加上了 attributes, attributeFilter 配置:

  • attributes 可选 当为 true 时观察所有监听的节点属性值的变化。默认值为 true,当声明了 attributeFilterattributeOldValue,默认值则为 false
  • attributeFilter 可选 一个用于声明哪些属性名会被监听的数组。如果不声明该属性,所有属性的变化都将触发通知。

当然监听dom的方法有很多 对于针对dom大小的监听也可以使用其他方法来实现,文末的React实现方案就是用 ResizeObserver 来监听的, 我们vue就以 MutationObserver 为例。

接下来写一个简单的hook,返回一个响应式的isDark变量,用于让我们的echarts组件监听即可,在此我定义为 isDark: boolean 的形式,如果涉及到多套主题的话,也可以对下面代码进行修改,把返回值改成 theme: 'dark', 字符串的形式。

ts复制代码/**
 * @name: 判断当前主题hook
 * @desc:
 * @return {*}
 */
export const useTheme = () => {
    const htmlDom = document.querySelector('html')
    if (!htmlDom) return { isDark: ref(false) }
    const isDark = ref(!!htmlDom.classList.contains('dark'))

    // 创建 MutationObserver 实例
    const observer = new MutationObserver((mutationsList) => {
        for (const mutation of mutationsList) {
            if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
                const currentClass = (mutation.target as any).className
                isDark.value = currentClass.includes('dark')
            }
        }
    })

    // 配置 MutationObserver 监听的选项
    const observerOptions = {
        attributes: true,
        attributeFilter: ['class'],
    }

    // 开始监听目标节点
    observer.observe(htmlDom, observerOptions)

    return {
        isDark
    }
}

有了这些前置条件,这不是咱们的组件就呼之欲出了,只需要修改 drawOption 方法进行中间颜色代理,并且增加一个监听器监听 isDark 变量即可。

vue复制代码<template>
    <div ref="domBox" :style="{ width, height }">
        <div ref="domRef" :style="{ width, height }" />
    </div>
</template>

<script lang="ts" setup>
import type { ECharts } from 'echarts'
import { watch, ref, onMounted, onUnmounted, nextTick } from 'vue'
import { replaceVarStrings, useTheme } from './utils'
import echarts from './index'
const props = defineProps({
    width: {
        type: String,
        default: '100%',
    },
    height: {
        type: String,
        default: '100%',
    },
    options: {
        type: Object,
        default: null,
    },
})
const { isDark } = useTheme()

const domRef = ref(null)
const domBox = ref(null)
let chartObj: null | ECharts = null
let observer: null | MutationObserver = null // dom 监听

onMounted(() => {
    if (!domRef.value) return
    init()
    drawOption()
    observer = new MutationObserver((mutationsList) => {
        for (const mutation of mutationsList)
            if (mutation.target === domBox.value) chartObj && chartObj.resize()
    })

    nextTick(() => {
        domBox.value && (observer as MutationObserver).observe(domBox.value, {
            attributes: true,
            childList: false,
            characterData: true,
            subtree: true
        })
    })

    setTimeout(() => {
        chartObj && chartObj.resize()
    }, 1000)
})

onUnmounted(() => {
    if (chartObj) {
        chartObj.dispose()
        chartObj = null
    }
    observer && observer.disconnect()
})

watch(() => props.options, () => drawOption())
watch(() => isDark.value, () => drawOption())

// 初始化
const init = () => {
    chartObj = (echarts.init(domRef.value) as any)
}

const drawOption = () => {
    if(!chartObj) return
    if(!props.options) {
        chartObj.clear()
        chartObj.showLoading({
            text: '',
            color: '#409eff',
            textColor: '#000',
            maskColor: 'rgba(255, 255, 255, .95)',
            zlevel: 0,
            lineWidth: 2,
        })
    }
    else {
        chartObj.hideLoading()
        chartObj.setOption(replaceVarStrings(props.options))
    }
}
</script>

lazy模式

为了提高组建的扩展性,我们也可以为组建增加一个非自动化的lazy模式。当我们开启了lazy模式以后,组建将不会自动的收集option依赖更新dom,也不用传入响应式的option,而是需要外部调用组建expose的方法控制更新时机。

vue复制代码<template>
    <div ref="domBox" :style="{ width, height }">
        <div ref="domRef" :style="{ width, height }" />
    </div>
</template>

<script lang="ts" setup>
import { watch, ref, onMounted, onUnmounted, nextTick } from 'vue'
import { replaceVarStrings, useTheme } from './utils'
import type { ECharts } from 'echarts'
import echarts from './index'
const props = defineProps({
    width: {
        type: String,
        default: '100%',
    },
    height: {
        type: String,
        default: '100%',
    },
    lazy: {
        type: Boolean,
        default: false,
    },
    options: {
        type: Object,
        default: null,
    },
})
const { isDark } = useTheme()

const domRef = ref(null)
const domBox = ref(null)
let chartObj: null | ECharts = null
let observer: null | MutationObserver = null // dom 监听

onMounted(() => {
    if (!domRef.value) return
    init()
    if(props.lazy) return
    drawOption()
    observer = new MutationObserver((mutationsList) => {
        for (const mutation of mutationsList)
            if (mutation.target === domBox.value) resize()
    })
    nextTick(() => {
        domBox.value && (observer as MutationObserver).observe(domBox.value, {
            attributes: true,
            childList: false,
            characterData: true,
            subtree: true
        })
    })
})

onUnmounted(() => {
    if (chartObj) {
        chartObj.dispose()
        chartObj = null
    }
    observer?.disconnect()
})

watch(() => props.options, () => !props.lazy && drawOption())
watch(() => isDark.value, () => !props.lazy && drawOption())

// 绘制方法
const drawOption = (options = props.options) => {
    if(!chartObj) return
    if(!options) {
        chartObj.clear()
        chartObj.showLoading({
            text: '',
            color: '#409eff',
            textColor: '#000',
            maskColor: 'rgba(255, 255, 255, .95)',
            zlevel: 0,
            lineWidth: 2,
        })
    }
    else {
        chartObj.hideLoading()
        chartObj.setOption(replaceVarStrings(options))
    }
}

// 初始化
const init = () => {
    chartObj = (echarts.init(domRef.value) as any)
}

// 重绘 自适应尺寸
const resize = () => {
    chartObj?.resize()
}

defineExpose({
    drawOption,
    resize,
    init
})
</script>

使用

vue复制代码<template>
    <div style="height: 300px;width: 200px;">
        <BaseECharts :options="options" />
    </div>
</template>
<script setup lang="ts">
import BaseECharts from '@/utils/echarts/BaseECharts.vue'
const options = ref<any>({
        xAxis: {
          type: 'category',
          data: [],
        },
        color: ['var(--dv-color-danger)'], // 颜色的变量字符串
        yAxis: {
          type: 'value',
        },
        series: [
          {
            data: [],
            type: 'line',
          },
        ],
  })

setTimeout(() => {
  options.value = {
        xAxis: {
          type: 'category',
          data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
        },
        color: ['var(--dv-color-danger)'], // 颜色的变量字符串
        yAxis: {
          type: 'value',
        },
        series: [
          {
            data: [150, 230, 224, 218, 135, 147, 260],
            type: 'line',
          },
        ],
    }
}, 3000)
</script>

react

对于react方案,我们在实现useTheme 上会有一些不一样,我们的变量需要用useState实现,注意 useState 避免放在条件return语句之后。 useTheme:

ts复制代码/**
 * @name: 判断当前主题hook
 * @desc:
 * @return {*}
 */
export const useTheme = () => {
    const htmlDom = document.querySelector('html');
    const [isDark, setIsDark] = useState(!!htmlDom?.classList.contains('dark'));
    const observer = useRef<MutationObserver>();
    if (!htmlDom) return { isDark: false };
    // 创建 MutationObserver 实例
    if (!observer.current) {
        observer.current = new MutationObserver((mutationsList) => {
            for (const mutation of mutationsList) {
                if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
                    const currentClass = (mutation.target as HTMLElement).className;
                    setIsDark(currentClass.includes('dark'));
                }
            }
        });
    }

    // 配置 MutationObserver 监听的选项
    const observerOptions = {
        attributes: true,
        attributeFilter: ['class'],
    };

    // 开始监听目标节点
    observer.current.observe(htmlDom, observerOptions);

    return {
        isDark,
    };
};

在组件实现这边我们换用更为简单的api ResizeObserver 接口可以监视 Element 内容盒或边框盒或者 SVGElement 边界尺寸的变化。

注意记得在 useEffect 的 return 语句中将我们的 ResizeObserver 监听器和实例销毁。

组件:

tsx复制代码/*
 * @Author: mjh
 * @Date: 2023-11-25 16:04:13
 * @LastEditors: mjh
 * @LastEditTime: 2023-11-25 23:23:28
 * @Description:
 */
import { useEffect, useRef } from 'react';
import echarts from './index';
import { replaceVarStrings, useTheme } from './utils';
export interface EchartControllerProps {
    width?: string;
    height?: string;
    options?: Record<string, any> | null;
}
export default function EchartController(props: EchartControllerProps) {
    const { height = '100%', width = '100%', options } = props;
    const chartRef = useRef<any>();
    const cInstance = useRef<any>();
    const { isDark } = useTheme();

    useEffect(() => {
        if (!chartRef.current) return;
        if (!cInstance.current) {
            cInstance.current = echarts.init(chartRef.current);
        }
        const observer = new ResizeObserver(() => {
            cInstance.current.resize();
        });
        observer.observe(chartRef.current);
        return () => {
            cInstance.current?.dispose()
            observer.disconnect();
        };
    }, []);

    useEffect(() => {
        if (!cInstance.current) return;
        if (!options) {
            cInstance.current.showLoading({
                text: '',
                color: '#409eff',
                textColor: '#000',
                maskColor: 'rgba(255, 255, 255, .95)',
                zlevel: 0,
                lineWidth: 2,
            });
            return;
        }
        cInstance.current.hideLoading();
        cInstance.current.setOption(replaceVarStrings(options));
    }, [options, isDark]);

    return (
      <div ref={chartRef} style={{ height, width }} />
    );
}

交互事件

  • 我的大部分项目都不会涉及到echarts交互事件,所以暂时没有封装。
  • 如果出现需求,可以简单做一个组件内部的事件代理即可,也可以根据需求做一些简单的语法弹,但是还是以场景和需求为准。

参考资料

developer.mozilla.org/zh-CN/docs/… developer.mozilla.org/zh-CN/docs/…

作者:Freedom风间 链接:https://juejin.cn/post/7304959484828844043 来源:稀土掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


相关推荐

驱动网卡(怎么从新驱动网卡)
驱动网卡(怎么从新驱动网卡)

网卡一般是指为电脑主机提供有线无线网络功能的适配器。而网卡驱动指的就是电脑连接识别这些网卡型号的桥梁。网卡只有打上了网卡驱动才能正常使用。并不是说所有的网卡一插到电脑上面就能进行数据传输了,他都需要里面芯片组的驱动文件才能支持他进行数据传输...

2026-01-30 00:37 liuian

win10更新助手装系统(微软win10更新助手)

1、点击首页“系统升级”的按钮,给出弹框,告诉用户需要上传IMEI码才能使用升级服务。同时给出同意和取消按钮。华为手机助手2、点击同意,则进入到“系统升级”功能华为手机助手华为手机助手3、在检测界面,...

windows11专业版密钥最新(windows11专业版激活码永久)

 Windows11专业版的正版密钥,我们是对windows的激活所必备的工具。该密钥我们可以通过微软商城或者通过计算机的硬件供应商去购买获得。获得了windows11专业版的正版密钥后,我...

手机删过的软件恢复(手机删除过的软件怎么恢复)
手机删过的软件恢复(手机删除过的软件怎么恢复)

操作步骤:1、首先,我们需要先打开手机。然后在许多图标中找到带有[文件管理]文本的图标,然后单击“文件管理”进入页面。2、进入页面后,我们将在顶部看到一行文本:手机,最新信息,文档,视频,图片,音乐,收藏,最后是我们正在寻找的[更多],单击...

2026-01-29 23:55 liuian

一键ghost手动备份系统步骤(一键ghost 备份)

  步骤1、首先把装有一键GHOST装系统的U盘插在电脑上,然后打开电脑马上按F2或DEL键入BIOS界面,然后就选择BOOT打USDHDD模式选择好,然后按F10键保存,电脑就会马上重启。  步骤...

怎么创建局域网(怎么创建局域网打游戏)

  1、购买路由器一台。进入路由器把dhcp功能打开  2、购买一台交换机。从路由器lan端口拉出一条网线查到交换机的任意一个端口上。  3、两台以上电脑。从交换机任意端口拉出网线插到电脑上(电脑设置...

精灵驱动器官方下载(精灵驱动手机版下载)

是的。驱动精灵是一款集驱动管理和硬件检测于一体的、专业级的驱动管理和维护工具。驱动精灵为用户提供驱动备份、恢复、安装、删除、在线更新等实用功能。1、全新驱动精灵2012引擎,大幅提升硬件和驱动辨识能力...

一键还原系统步骤(一键还原系统有哪些)

1、首先需要下载安装一下Windows一键还原程序,在安装程序窗口中,点击“下一步”,弹出“用户许可协议”窗口,选择“我同意该许可协议的条款”,并点击“下一步”。  2、在弹出的“准备安装”窗口中,可...

电脑加速器哪个好(电脑加速器哪款好)

我认为pp加速器最好用,飞速土豆太懒,急速酷六根本不工作。pp加速器什么网页都加速,太任劳任怨了!以上是个人观点,具体性能请自己试。ps:我家电脑性能很好。迅游加速盒子是可以加速电脑的。因为有过之...

任何u盘都可以做启动盘吗(u盘必须做成启动盘才能装系统吗)

是的,需要注意,U盘的大小要在4G以上,最好是8G以上,因为启动盘里面需要装系统,内存小的话,不能用来安装系统。内存卡或者U盘或者移动硬盘都可以用来做启动盘安装系统。普通的U盘就可以,不过最好U盘...

u盘怎么恢复文件(u盘文件恢复的方法)

开360安全卫士,点击上面的“功能大全”。点击文件恢复然后点击“数据”下的“文件恢复”功能。选择驱动接着选择需要恢复的驱动,选择接入的U盘。点击开始扫描选好就点击中间的“开始扫描”,开始扫描U盘数据。...

系统虚拟内存太低怎么办(系统虚拟内存占用过高什么原因)

1.检查系统虚拟内存使用情况,如果发现有大量的空闲内存,可以尝试释放一些不必要的进程,以释放内存空间。2.如果系统虚拟内存使用率较高,可以尝试增加系统虚拟内存的大小,以便更多的应用程序可以使用更多...

剪贴板权限设置方法(剪贴板访问权限)
剪贴板权限设置方法(剪贴板访问权限)

1、首先打开iphone手机,触碰并按住单词或图像直到显示选择选项。2、其次,然后选取“拷贝”或“剪贴板”。3、勾选需要的“权限”,最后选择开启,即可完成苹果剪贴板权限设置。仅参考1.打开苹果手机设置按钮,点击【通用】。2.点击【键盘】,再...

2026-01-29 21:37 liuian

平板系统重装大师(平板重装win系统)

如果你的平板开不了机,但可以连接上电脑,那就能好办,楼主下载安装个平板刷机王到你的个人电脑上,然后连接你的平板,平板刷机王会自动识别你的平板,平板刷机王上有你平板的我刷机包,楼主点击下载一个,下载完成...

联想官网售后服务网点(联想官网售后服务热线)

联想3c服务中心是联想旗下的官方售后,是基于互联网O2O模式开发的全新服务平台。可以为终端用户提供多品牌手机、电脑以及其他3C类产品的维修、保养和保险服务。根据客户需求层次,联想服务针对个人及家庭客户...