Vue3水印(Watermark)

APIs

参数说明类型默认值必传
width水印的宽度,默认值为 content 自身的宽度numberundefinedfalse
height水印的高度,默认值为 content 自身的高度numberundefinedfalse
rotate水印绘制时,旋转的角度,单位 °number-22false
zIndex追加的水印元素的 z-indexnumber9false
image图片源,建议使用 2 倍或 3 倍图,优先级高于文字stringundefinedfalse
content水印文字内容string | string[]‘’false
color字体颜色string‘rgba(0,0,0,.15)’false
fontSize字体大小,单位pxnumber16false
fontWeight字体粗细‘normal’ | ‘light’ | ‘weight’ | number‘normal’false
fontFamily字体类型string‘sans-serif’false
fontStyle字体样式‘none’ | ‘normal’ | ‘italic’ | ‘oblique’‘normal’false
gap水印之间的间距[number, number][100, 100]false
offset水印距离容器左上角的偏移量,默认为 gap/2[number, number][50, 50]false

效果如下图:在线预览

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

创建水印组件Watermark.vue

<script setup lang="ts">
import {
  unref,
  shallowRef,
  computed,
  watch,
  onMounted,
  onBeforeUnmount,
  nextTick,
  getCurrentInstance,
  getCurrentScope,
  onScopeDispose
} from 'vue'
import type { CSSProperties } from 'vue'
interface Props {
  width?: number // 水印的宽度,默认值为 content 自身的宽度
  height?: number // 水印的高度,默认值为 content 自身的高度
  rotate?: number // 水印绘制时,旋转的角度,单位 °
  zIndex?: number // 追加的水印元素的 z-index
  image?: string // 图片源,建议使用 2 倍或 3 倍图,优先级高于文字
  content?: string|string[] // 水印文字内容
  color?: string // 字体颜色
  fontSize?: number // 字体大小
  fontWeight?: 'normal'|'light'|'weight'|number // 	字体粗细
  fontFamily?: string // 字体类型
  fontStyle?: 'none'|'normal'|'italic'|'oblique' // 字体样式
  gap?: [number, number] // 水印之间的间距
  offset?: [number, number] // 水印距离容器左上角的偏移量,默认为 gap/2
}
const props = withDefaults(defineProps<Props>(), {
  width: undefined,
  height: undefined,
  rotate: -22,
  zIndex: 9,
  image: undefined,
  content: '',
  color: 'rgba(0,0,0,.15)',
  fontSize: 16,
  fontWeight: 'normal',
  fontFamily: 'sans-serif',
  fontStyle: 'normal',
  gap: () => [100, 100],
  offset: () => [50, 50]
})
/**
 * Base size of the canvas, 1 for parallel layout and 2 for alternate layout
 */
const BaseSize = 2
const FontGap = 3
// 和 ref() 不同,浅层 ref 的内部值将会原样存储和暴露,并且不会被深层递归地转为响应式。只有对 .value 的访问是响应式的。
const containerRef = shallowRef() // ref() 的浅层作用形式
const watermarkRef = shallowRef()
const stopObservation = shallowRef(false)
const gapX = computed(() => props.gap?.[0] ?? 100)
const gapY = computed(() => props.gap?.[1] ?? 100)
const gapXCenter = computed(() => gapX.value / 2)
const gapYCenter = computed(() => gapY.value / 2)
const offsetLeft = computed(() => props.offset?.[0] ?? gapXCenter.value)
const offsetTop = computed(() => props.offset?.[1] ?? gapYCenter.value)
const markStyle = computed(() => {
  const markStyle: CSSProperties = {
    zIndex: props.zIndex ?? 9,
    position: 'absolute',
    left: 0,
    top: 0,
    width: '100%',
    height: '100%',
    pointerEvents: 'none',
    backgroundRepeat: 'repeat'
  }
  /** Calculate the style of the offset */
  let positionLeft = offsetLeft.value - gapXCenter.value
  let positionTop = offsetTop.value - gapYCenter.value
  if (positionLeft > 0) {
    markStyle.left = `${positionLeft}px`
    markStyle.width = `calc(100% - ${positionLeft}px)`
    positionLeft = 0
  }
  if (positionTop > 0) {
    markStyle.top = `${positionTop}px`
    markStyle.height = `calc(100% - ${positionTop}px)`
    positionTop = 0
  }
  markStyle.backgroundPosition = `${positionLeft}px ${positionTop}px`

  return markStyle
})
const destroyWatermark = () => {
  if (watermarkRef.value) {
    watermarkRef.value.remove()
    watermarkRef.value = undefined
  }
}
const appendWatermark = (base64Url: string, markWidth: number) => {
  if (containerRef.value && watermarkRef.value) {
    stopObservation.value = true
    watermarkRef.value.setAttribute(
      'style',
      getStyleStr({
        ...markStyle.value,
        backgroundImage: `url('${base64Url}')`,
        backgroundSize: `${(gapX.value + markWidth) * BaseSize}px`
      })
    )
    containerRef.value?.append(watermarkRef.value)
    // Delayed execution
    setTimeout(() => {
      stopObservation.value = false
    })
  }
}
// converting camel-cased strings to be lowercase and link it with Separator
function toLowercaseSeparator(key: string) {
  return key.replace(/([A-Z])/g, '-$1').toLowerCase()
}
function getStyleStr(style: CSSProperties): string {
  return Object.keys(style)
    .map((key: any) => `${toLowercaseSeparator(key)}: ${style[key]};`)
    .join(' ')
}
/*
  Get the width and height of the watermark. The default values are as follows
  Image: [120, 64]; Content: It's calculated by content
*/
const getMarkSize = (ctx: CanvasRenderingContext2D) => {
  let defaultWidth = 120
  let defaultHeight = 64
  const content = props.content
  const image = props.image
  const width = props.width
  const height = props.height
  const fontSize = props.fontSize
  const fontFamily = props.fontFamily
  if (!image && ctx.measureText) {
    ctx.font = `${Number(fontSize)}px ${fontFamily}`
    const contents = Array.isArray(content) ? content : [content]
    const widths = contents.map(item => ctx.measureText(item!).width)
    defaultWidth = Math.ceil(Math.max(...widths))
    defaultHeight = Number(fontSize) * contents.length + (contents.length - 1) * FontGap
  }
  return [width ?? defaultWidth, height ?? defaultHeight] as const
}
// Returns the ratio of the device's physical pixel resolution to the css pixel resolution
function getPixelRatio () {
  return window.devicePixelRatio || 1
}
const fillTexts = (
  ctx: CanvasRenderingContext2D,
  drawX: number,
  drawY: number,
  drawWidth: number,
  drawHeight: number,
) => {
  const ratio = getPixelRatio()
  const content = props.content
  const fontSize = props.fontSize
  const fontWeight = props.fontWeight
  const fontFamily = props.fontFamily
  const fontStyle = props.fontStyle
  const color = props.color
  const mergedFontSize = Number(fontSize) * ratio
  ctx.font = `${fontStyle} normal ${fontWeight} ${mergedFontSize}px/${drawHeight}px ${fontFamily}`
  ctx.fillStyle = color
  ctx.textAlign = 'center'
  ctx.textBaseline = 'top'
  ctx.translate(drawWidth / 2, 0)
  const contents = Array.isArray(content) ? content : [content]
  contents?.forEach((item, index) => {
    ctx.fillText(item ?? '', drawX, drawY + index * (mergedFontSize + FontGap * ratio))
  })
}
const renderWatermark = () => {
  const canvas = document.createElement('canvas')
  const ctx = canvas.getContext('2d')
  const image = props.image
  const rotate = props.rotate ?? -22

  if (ctx) {
    if (!watermarkRef.value) {
      watermarkRef.value = document.createElement('div')
    }

    const ratio = getPixelRatio()
    const [markWidth, markHeight] = getMarkSize(ctx)
    const canvasWidth = (gapX.value + markWidth) * ratio
    const canvasHeight = (gapY.value + markHeight) * ratio
    canvas.setAttribute('width', `${canvasWidth * BaseSize}px`)
    canvas.setAttribute('height', `${canvasHeight * BaseSize}px`)

    const drawX = (gapX.value * ratio) / 2
    const drawY = (gapY.value * ratio) / 2
    const drawWidth = markWidth * ratio
    const drawHeight = markHeight * ratio
    const rotateX = (drawWidth + gapX.value * ratio) / 2
    const rotateY = (drawHeight + gapY.value * ratio) / 2
    /** Alternate drawing parameters */
    const alternateDrawX = drawX + canvasWidth
    const alternateDrawY = drawY + canvasHeight
    const alternateRotateX = rotateX + canvasWidth
    const alternateRotateY = rotateY + canvasHeight

    ctx.save()
    rotateWatermark(ctx, rotateX, rotateY, rotate)

    if (image) {
      const img = new Image()
      img.onload = () => {
        ctx.drawImage(img, drawX, drawY, drawWidth, drawHeight)
        /** Draw interleaved pictures after rotation */
        ctx.restore()
        rotateWatermark(ctx, alternateRotateX, alternateRotateY, rotate)
        ctx.drawImage(img, alternateDrawX, alternateDrawY, drawWidth, drawHeight)
        appendWatermark(canvas.toDataURL(), markWidth)
      }
      img.crossOrigin = 'anonymous'
      img.referrerPolicy = 'no-referrer'
      img.src = image
    } else {
      fillTexts(ctx, drawX, drawY, drawWidth, drawHeight)
      /** Fill the interleaved text after rotation */
      ctx.restore()
      rotateWatermark(ctx, alternateRotateX, alternateRotateY, rotate)
      fillTexts(ctx, alternateDrawX, alternateDrawY, drawWidth, drawHeight)
      appendWatermark(canvas.toDataURL(), markWidth)
    }
  }
}
// Rotate with the watermark as the center point
function rotateWatermark(
  ctx: CanvasRenderingContext2D,
  rotateX: number,
  rotateY: number,
  rotate: number
) {
  ctx.translate(rotateX, rotateY)
  ctx.rotate((Math.PI / 180) * Number(rotate))
  ctx.translate(-rotateX, -rotateY)
}
onMounted(() => {
  renderWatermark()
})
watch(
  () => [props],
  () => {
    renderWatermark()
  },
  {
    deep: true, // 强制转成深层侦听器
    flush: 'post' // 在侦听器回调中访问被 Vue 更新之后的 DOM
  },
)
onBeforeUnmount(() => {
  destroyWatermark()
})
// Whether to re-render the watermark
const reRendering = (mutation: MutationRecord, watermarkElement?: HTMLElement) => {
  let flag = false
  // Whether to delete the watermark node
  if (mutation.removedNodes.length) {
    flag = Array.from(mutation.removedNodes).some(node => node === watermarkElement)
  }
  // Whether the watermark dom property value has been modified
  if (mutation.type === 'attributes' && mutation.target === watermarkElement) {
    flag = true
  }
  return flag
}
const onMutate = (mutations: MutationRecord[]) => {
  if (stopObservation.value) {
    return
  }
  mutations.forEach(mutation => {
    if (reRendering(mutation, watermarkRef.value)) {
      destroyWatermark()
      renderWatermark()
    }
  })
}
const defaultWindow = typeof window !== 'undefined' ? window : undefined
type Fn = () => void
function tryOnMounted(fn: Fn, sync = true) {
  if (getCurrentInstance()) onMounted(fn)
  else if (sync) fn()
  else nextTick(fn)
}
function useSupported(callback: () => unknown, sync = false) {
  const isSupported = shallowRef<boolean>()
  const update = () => (isSupported.value = Boolean(callback()))
  update()
  tryOnMounted(update, sync)
  return isSupported
}
function useMutationObserver(
  target: any,
  callback: MutationCallback,
  options: any,
) {
  const { window = defaultWindow, ...mutationOptions } = options
  let observer: MutationObserver | undefined
  const isSupported = useSupported(() => window && 'MutationObserver' in window)

  const cleanup = () => {
    if (observer) {
      observer.disconnect()
      observer = undefined
    }
  }

  const stopWatch = watch(
    () => unref(target),
    el => {
      cleanup()

      if (isSupported.value && window && el) {
        observer = new MutationObserver(callback)
        observer!.observe(el, mutationOptions)
      }
    },
    { immediate: true }
  )

  const stop = () => {
    cleanup()
    stopWatch()
  }

  tryOnScopeDispose(stop)

  return {
    isSupported,
    stop
  }
}
function tryOnScopeDispose(fn: Fn) {
  if (getCurrentScope()) {
    onScopeDispose(fn)
    return true
  }
  return false
}
useMutationObserver(containerRef, onMutate, {
  attributes: true // 观察所有监听的节点属性值的变化
})
</script>
<template>
  <div ref="containerRef" style="position: relative;">
    <slot></slot>
  </div>
</template>

在要使用的页面引入

<script setup lang="ts">
import Watermark from './Watermark.vue'
import { reactive } from 'vue'
const model = reactive({
  content: 'Vue Amazing UI',
  color: 'rgba(0,0,0,.15)',
  fontSize: 16,
  fontWeight: 400,
  zIndex: 9,
  rotate: -22,
  gap: [100, 100],
  offset: [50, 50]
})
</script>
<template>
  <div>
    <h1>Watermark 水印</h1>
    <h2 class="mt30 mb10">基本使用</h2>
    <Watermark content="Vue Amazing UI">
      <div style="height: 360px" />
    </Watermark>
    <h2 class="mt30 mb10">多行水印</h2>
    <h3 class="mb10">通过 content 设置 字符串数组 指定多行文字水印内容。</h3>
    <Watermark :content="['Vue Amazing UI', 'Hello World']">
      <div style="height: 400px" />
    </Watermark>
    <h2 class="mt30 mb10">图片水印</h2>
    <h3 class="mb10">通过 image 指定图片地址。为保证图片高清且不被拉伸,请设置 width 和 height, 并上传至少两倍的宽高的 logo 图片地址。</h3>
    <Watermark
      :height="30"
      :width="130"
      image="https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*lkAoRbywo0oAAAAAAAAAAAAADrJ8AQ/original">
      <div style="height: 360px" />
    </Watermark>
    <h2 class="mt30 mb10">自定义配置</h2>
    <h3 class="mb10">通过自定义参数配置预览水印效果。</h3>
    <Flex>
      <Watermark v-bind="model">
        <p class="u-paragraph">
          The light-speed iteration of the digital world makes products more complex. However, human
          consciousness and attention resources are limited. Facing this design contradiction, the
          pursuit of natural interaction will be the consistent direction of Ant Design.
        </p>
        <p class="u-paragraph">
          Natural user cognition: According to cognitive psychology, about 80% of external
          information is obtained through visual channels. The most important visual elements in the
          interface design, including layout, colors, illustrations, icons, etc., should fully
          absorb the laws of nature, thereby reducing the user&apos;s cognitive cost and bringing
          authentic and smooth feelings. In some scenarios, opportunely adding other sensory
          channels such as hearing, touch can create a richer and more natural product experience.
        </p>
        <p class="u-paragraph">
          Natural user behavior: In the interaction with the system, the designer should fully
          understand the relationship between users, system roles, and task objectives, and also
          contextually organize system functions and services. At the same time, a series of methods
          such as behavior analysis, artificial intelligence and sensors could be applied to assist
          users to make effective decisions and reduce extra operations of users, to save
          users&apos; mental and physical resources and make human-computer interaction more
          natural.
        </p>
        <img
          style=" position: relative; z-index: 1; width: 100%; max-width: 800px;"
          src="https://cdn.jsdelivr.net/gh/themusecatcher/resources@0.0.3/6.jpg"
          alt="示例图片"
        />
      </Watermark>
      <Flex
        style="
          width: 25%;
          flex-shrink: 0;
          border-left: 1px solid #eee;
          padding-left: 20px;
          margin-left: 20px;
        "
        vertical
        gap="middle"
      >
        <p>Content</p>
        <Input v-model:value="model.content" />
        <p>Color</p>
        <Input v-model:value="model.color" />
        <p>FontSize</p>
        <Slider v-model:value="model.fontSize" :step="1" :min="0" :max="100" />
        <p>FontWeight</p>
        <InputNumber v-model:value="model.fontWeight" :step="100" :min="100" :max="1000" />
        <p>zIndex</p>
        <Slider v-model:value="model.zIndex" :step="1" :min="0" :max="100" />
        <p>Rotate</p>
        <Slider v-model:value="model.rotate" :step="1" :min="-180" :max="180" />
        <p>Gap</p>
        <Space style="display: flex" align="baseline">
          <InputNumber v-model:value="model.gap[0]" :min="0" placeholder="gapX" />
          <InputNumber v-model:value="model.gap[1]" :min="0" placeholder="gapY" />
        </Space>
        <p>Offset</p>
        <Space style="display: flex" align="baseline">
          <InputNumber v-model:value="model.offset[0]" :min="0" placeholder="offsetLeft" />
          <InputNumber v-model:value="model.offset[1]" :min="0" placeholder="offsetTop" />
        </Space>
      </Flex>
    </Flex>
  </div>
</template>
<style>
.u-paragraph {
  margin-bottom: 1em;
  color: rgba(0, 0, 0, .88);
  word-break: break-word;
  line-height: 1.5714285714285714;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/200699.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

oracle官方的反解析工具:javap详解

1、解析字节码的作用 通过反编译生成的字节码文件&#xff0c;我们可以深入的了解java代码的工作机制。但是&#xff0c;自己分析类文件结构太麻烦了&#xff01;除了使用第三方的jclasslib工具之外&#xff0c;oracle官方也提供了工具&#xff1a;javap javap是jdk自带的反解…

数据结构与算法之美学习笔记:28 | 堆和堆排序:为什么说堆排序没有快速排序快?

目录 前言如何理解“堆”&#xff1f;如何实现一个堆&#xff1f;1. 往堆中插入一个元素2. 删除堆顶元素 如何基于堆实现排序&#xff1f;1. 建堆2. 排序 解答开篇内容小结 前言 本节课程思维导图&#xff1a; 我们今天讲另外一种特殊的树&#xff0c;“堆”&#xff08;Heap&…

【蓝桥杯选拔赛真题69】Scratch洗牌发牌 少儿编程scratch图形化编程 蓝桥杯创意编程选拔赛真题解析

目录 scratch洗牌发牌 一、题目要求 编程实现 二、案例分析 1、角色分析

2023年大数据场景智能运维实践总结

作者&#xff1a;放纵 引言 在当今数字化世界中&#xff0c;如何充分挖掘和发挥数据价值已经成为了企业成功的关键因素&#xff0c;大数据也成为企业决策和运营的重要驱动力。在《当我们在谈论DataOps时&#xff0c;我们到底在谈论什么》一文中也提到&#xff0c;企业在面对到…

P8A004-系统加固-磁盘访问权限

【预备知识】 访问权限&#xff0c;根据在各种预定义的组中用户的身份标识及其成员身份来限制访问某些信息项或某些控制的机制。访问控制通常由系统管理员用来控制用户访问网络资源&#xff08;如服务器、目录和文件&#xff09;的访问&#xff0c;并且通常通过向用户和组授予…

数据结构与算法--特殊的完全二叉树--堆,堆排序,利用堆解决topk的问题

目录 前言 1.树概念及结构 1.1树的概念 1.2 树的相关概念 1.3 树的表示 1.4 树在实际中的运用&#xff08;表示文件系统的目录树结构&#xff09; 2.二叉树概念及结构 2.1概念 2.2现实中的二叉树&#xff1a; 2.3 特殊的二叉树&#xff1a; 2.4 二叉树的性质 …

网络协议系列:TCP三次握手,四次挥手的全过程,为什么需要三次握手,四次挥手

TCP三次握手&#xff0c;四次挥手的全过程&#xff0c;为什么需要三次握手&#xff0c;四次挥手 一. TCP三次握手&#xff0c;四次挥手的全过程&#xff0c;为什么需要三次握手&#xff0c;四次挥手前言TCP协议的介绍三次握手三次握手流程&#xff1a;1. A 的 TCP 向 B 发送 连…

Windows关闭端口服务命令

winR 打开命令运行 cmd 命令netstat -o -n -a | findstr :9993 显示所有的端口占用情况 -a 显示所有连接和监听端口 -n 以数字形式显示地址和端口号。 此选项一般与 -a选项组合使用 -o 显示与每个连接相关的所属进程 ID 终止 PID taskkill /F /PID 3652

从独立求存到登顶市场,荣耀为何能在手机红海翻出新的浪花?

对企业的价值评估&#xff0c;往往离不开对其所处行业前景的考量。在蓝海赛道布局的企业&#xff0c;往往要比在红海市场突围的企业更容易受到资本重视。 但这并非绝对&#xff0c;若是一家企业能够在饱和的红海市场中&#xff0c;实现新的增长&#xff0c;其蕴涵的成长价值便…

Influx集群解决方案(Influx Proxy篇)

InFluxDB 集群搭建 本次搭建使用influx proxy 介绍 github地址:https://github.com/chengshiwen/influx-proxy/ Influx Proxy 是一个基于高可用、一致性哈希的 InfluxDB 集群代理服务&#xff0c;实现了 InfluxDB 高可用集群的部署方案&#xff0c; 具有动态扩/缩容、故障恢复…

字符串函数精讲1

又是好几天没有更新了&#xff0c;最近有些忙&#xff0c;但这并不是理由&#xff0c;还是怪我自己玩的时间多了&#xff01;但还是有在每天敲代码的&#xff01;话不多说&#xff0c;开始这一期的学习&#xff1a; strlen的使用和模拟实现 • 字符串以 \0 作为结束标志&#…

java学习part24异常throws

127-异常处理-异常处理方式二&#xff1a;throws_哔哩哔哩_bilibili 1.方法throws 2.如何抉择try和throws 3.手动throw语句 抛出一些java语法上没错但是不符合实际情况的异常。 用throw手动抛&#xff0c;方法上必须加throws。除非是运行时异常。 4.自定义异常

Java常见CodeReview及编码规范

鉴于自己的开发经验,以及常见容易产生bug及性能问题的点做个记录. 1.数据库 如果开发人员的经验不足,Java通过ORM(Mybatis)对数据库的操作的性能问题比较隐蔽.因为不压测或者异常case没发生的时候一般发现不了问题.特别是异常case发生的时候. 除配置表以外的sql都要经过expl…

软件设计师——程序设计语言基础(一)

&#x1f4d1;前言 本文主要是【程序设计语言基础】——程序设计语言基础的相关题目&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#…

荣耀冲击高端,一边推新「修路」,一边降价「拆桥」

作者 | 辰纹 来源 | 洞见新研社 从2020年11月17日与华为分家&#xff0c;开启独立创业之路&#xff0c;到成功逆袭&#xff0c;今年第三季度以18%的份额重回中国智能手机市场榜首&#xff0c;荣耀用了3年时间。 图源&#xff1a;Canalys 在这三年时间内&#xff0c;荣耀经历…

【算法萌新闯力扣】:环形链表及环形链表II

力扣题目&#xff1a;环形链表及环形链表II 开篇 今天是备战蓝桥杯的第26天和算法村开营第4天。挑选了链表的黄金关卡与大家分享。 题目一&#xff1a;环形链表 题目链接: 141.环形链表 题目描述 方法一、哈希表 判断是否有环&#xff0c;可以利用哈希表&#xff0c;遍历…

‘tsc‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

最近在用nodejs typescript 某游戏服务器在做一些研究 nodejs-tcs 问题描述&#xff1a; 1.使用命令npm install -g typescript安装typescript后&#xff0c;输入 tsc命令&#xff0c;一直报错 tsc 不是内部或外部命令&#xff0c;也不是可运行的程序 或批处理文件。 2.目…

算法面试题--树与对象数组的转化

1. Array -> Tree var arr [{ id: 12, parentId: 1, name: "朝阳区" },{ id: 241, parentId: 24, name: "田林街道" },{ id: 31, parentId: 3, name: "广州市" },{ id: 13, parentId: 1, name: "昌平区" },{ id: 2421, parentId:…

<Linux>(极简关键、省时省力)《Linux操作系统原理分析之存储管理(1)》(14)

[TOC](《Linux操作系统原理分析之存储管理》&#xff08;14&#xff09; 5 存储管理5.1 存储管理的目的和功能5.1.1 存储管理目的&#xff1a;5.1.2 存储管理的主要功能5.1.3 存储管理主要是对用户区进行管理 5.2 地址重定位5.2.1 作业的地址空间5.2.2&#xff0e;地址映射&…

Linux基本指令汇总

本专栏内容为&#xff1a;Linux学习专栏&#xff0c;分为系统和网络两部分。 通过本专栏的深入学习&#xff0c;你可以了解并掌握Linux。 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;Linux从入门到精通 &#x1f69a;代码仓库&#xff1a;小…