教你利用Vue3模仿Windows窗口

目录
  • 一、前言
  • 二、功能分析
  • 三、指令封装
  • 四、通用组件封装
  • 五、总结及其源代码参考
  • 六、博文参考

一、前言

Vue3终于在2022年2月7日正式发布了,之前用vite+vue3搭了一个小demo,资料太少而我太菜了,所以一直不敢用Vue3搭新项目,现在随着Vue3正式版本的发布,而且相关配合的子项目库也已经完善,大量的翻译资料和文献都已经可以百度到了,再加上领导支持用Vue3新框架,所以我在新项目上着手用vue-cli(@vue/cli 4.5.9)脚手架搭建Vue3项目。

图1 拖拽窗体效果展示

主要需求是做一个可以拖动并且放大缩小的窗体,类似于系统桌面的窗口,功能是可拖动然后宽高可通过鼠标拖拽调整,查阅了大量的博文后,打算基于Vue的自定义指令directive来实现,指令便于引用,而且使用的功能并不需要按照使用场景特殊化的修改,所以可以将这两个功能封装到指令中,然后基于这两个指令(v-drag、v-resize)再去封装一个通用窗体容器组件,项目框架基于Vue3+TS来实现,由于TS是刚上手,所以基本any一把梭,希望各位大佬莫要嘲笑,不熟悉TS的同学也可以看着代码实现一套JS版本的,主要功能都是JS基本功,和框架、语言的关系不大,只要能理解实现方法,简单的三剑客也能实现这个功能。接下来着手实现这个组件吧。

二、功能分析

图2 dom对象属性

Event对象属性

因为是拖动和改变元素尺寸大小的功能,所以需要知道JS元素中的几个属性,如上图所示,我们需要知道的如下所示:

  • Dom对象属性

    • offsetTop: 返回当前元素上边界到其上级元素(offsetParent)的上边界的距离【只读】
    • offsetLeft: 返回当前元素左边界到其上级元素(offsetParent)的左边界的距离【只读】
    • offsetWidth: 返回元素的宽度,包含padding+border-width【只读】
    • offsetHeight: 返回元素的高度,包含padding+border-width 【只读】
    • clientWidth: 返回元素的宽度
    • clientHeight: 返回元素的高度
  • Event对象属性
    • offsetX: 相对于元素的横坐标
    • offsetY: 相对于元素的纵坐标
    • clientX: 相对于浏览器窗口的横坐标
    • clientY: 相对于浏览器窗口的纵坐标
    • pageX: 相对于页面的横坐标
    • pageY: 相对于页面的纵坐标

熟悉这几个属性后就可以着手来实现拖动和尺寸调整了,主要实现思路如下:

  • v-drag 将该指令挂载到第一个子元素,然后通过监听子元素的事件来实现,通过子元素先获取到父元素方便后续对其进行操作,当鼠标按下事件触发的时候开始对鼠标移动事件监听,按下的时候需要记录鼠标所在位置的x,y轴的坐标值(相对于页面的位置x,y),然后记录拖动前父元素的top,left的数值,再获取窗口的宽高,减去父元素本身的宽高,计算得到父元素所能移动的最大位移距离,超过距离不能再移动。最后通过mousemove开始实时计算鼠标位移距离,并将变化的位移距离更新到父元素,实现元素的移动功能。
  • v-resize 调整元素宽高的指令有一些复杂,需要给元素指定一个name属性为resize,绑定该指令不能覆盖预设的name值,然后通过name属性确定是该元素。这里先定义一些需要记录的属性数据,首先是cursor的属性值,cursor是css中的指定鼠标样式的属性,这里一共8个方位,所以分别列出这些属性,并和top、bottom、left、right做一个关系映射,这样方便理解,也容易操作。然后是记录元素修改前的大小、位置、鼠标按下的位置、改变方向,定义完这些变量后,对一些特殊的方法进行聚合,首先是获取鼠标的方位,通过计算鼠标在元素内移动的位置,设置一个内边距触发计算方法,这里设置offset偏移量为12px,当鼠标在元素水平或垂直距离边框为12px的时候,就可以通过getDirection获取到鼠标所在的方位。再定义一个computedDistance 方法,用于计算鼠标前后移动的x,y的距离,最后就是计算改变尺寸方法的封装,changeSize方法中获取到鼠标位移的距离,然后结合移动的方向记录值,进行方法调用修改尺寸,方法中只将一半做了最小宽高设置,这里可以通过css来设置不用在js中编写,后续组件封装会看到。同样触发的方式是onmousedown的时候开启事件,这里会获取是否在8个方位范围上,如果在就记录按下按钮时的数据和方位,并且触发移动计算方法,鼠标按钮抬起释放的时候会对数据和方法重置,结束尺寸调整。 鼠标样式控制可以分开来看,主要对于宽高调整没有影响,监听8个方位,然后修改鼠标样式,使交互操作更加友好。

三、指令封装

v-drag与v-resize指令:

//directives.ts
import { App } from "vue";
import { throttle } from "@/utils"; //节流函数不再展示,不要直接去除即可,在下面样式引用去除即可

const directives = {
  drag: {
    mounted(el: any, binding: any, vnode: any) {
      // 如果传递了false就不启用指令,反之true undefined null 不传 则启动
      if (!binding.value && (binding.value ?? "") !== "") return;
      // 拖拽实现
      const odiv = el.parentNode;
      el.onmousedown = (eve: any) => {
        odiv.style.zIndex = 1; //当前拖拽的在最前面显示
        eve = eve || window.event;
        const mx = eve.pageX; //鼠标点击时的坐标
        const my = eve.pageY; //鼠标点击时的坐标
        const dleft = odiv.offsetLeft; //窗口初始位置
        const dtop = odiv.offsetTop;
        const clientWidth = document.documentElement.clientWidth; //页面的宽
        const oWidth = odiv.clientWidth; //窗口的宽
        const maxX = clientWidth - oWidth; // x轴能移动的最大距离
        const clientHeight = document.documentElement.clientHeight; //页面的高
        const oHeight = odiv.clientHeight; //窗口的高度
        const maxY = clientHeight - oHeight; //y轴能移动的最大距离
        document.onmousemove = (e: any) => {
          const x = e.pageX;
          const y = e.pageY;
          let left = x - mx + dleft; //移动后的新位置
          let top = y - my + dtop; //移动后的新位置
          if (left < 0) left = 0;
          if (left > maxX) left = maxX;
          if (top < 0) top = 0;
          if (top > maxY) top = maxY;

          odiv.style.left = left + "px";
          odiv.style.top = top + "px";
          odiv.style.marginLeft = 0;
          odiv.style.marginTop = 0;
        };
        document.onmouseup = () => {
          document.onmousemove = null;
        };
      };
    }
  },
  resize: {
    mounted(el: any, binding: any, vnode: any) {
      // 如果传递了false就不启用指令,反之true undefined null 不传 则启动
      if (!binding.value && (binding.value ?? "") !== "") return;
      // 给选定的元素绑定name属性 设置name为resize区分只有该元素可以缩放
      el.name = "resize";
      // 八个方位对应
      const mouseDir = {
        top: "n-resize", //上
        bottom: "s-resize", //下
        left: "w-resize", //左
        right: "e-resize", //右
        topright: "ne-resize", //右上
        topleft: "nw-resize", //左上
        bottomleft: "sw-resize", //左下
        bottomright: "se-resize" //右下
      };
      // 记录被修改元素的原始位置大小,以及变更方向
      const pos = { width: 0, height: 0, top: 0, left: 0, x: 0, y: 0, dir: "" };
      // 获取鼠标所在方位
      const getDirection = (ev: any): string => {
        let dir = "";
        const xP = ev.offsetX;
        const yP = ev.offsetY;
        const offset = 12; //内边距为多少时触发
        // 计算是那个方位
        if (yP < offset) dir += "top";
        else if (yP > ev.toElement.clientHeight - offset) dir += "bottom";
        if (xP < offset) dir += "left";
        else if (xP > ev.toElement.clientWidth - offset) dir += "right";
        return dir;
      };
      // 计算移动距离
      const computedDistance = (pre: any, cur: any): any => {
        return [cur.x - pre.x, cur.y - pre.y];
      };
      //数据重置
      const resetData = () => {
        pos.width = 0;
        pos.height = 0;
        pos.top = 0;
        pos.left = 0;
        pos.x = 0;
        pos.y = 0;
        pos.dir = "";
        document.onmousemove = null;
      };
      // 变更尺寸方法
      const changeSize = (e: any) => {
        // 两个点之间的差值,计算鼠标位移数值
        const [disX, disY] = computedDistance(
          { x: pos.x, y: pos.y },
          { x: e.pageX, y: e.pageY }
        );
        const addWid = pos.width + disX;
        const subWid = pos.width - disX;
        const addHig = pos.height + disY;
        const subHig = pos.height - disY;
        const minX = 200;
        const minY = 200;
        //上下左右的变更方法
        const top = () => {
          if (subHig <= minY) return; //不能小于最小最高
          el.style.height = subHig + "px";
          el.style.top = pos.top + disY + "px";
        }; // 上
        const bottom = () => {
          el.style.height = addHig + "px";
        }; // 下
        const left = () => {
          if (subWid <= minX) return; //不能小于最小宽度
          el.style.width = subWid + "px";
          el.style.left = pos.left + disX + "px";
        }; // 左
        const right = () => {
          el.style.width = addWid + "px";
        }; // 右
        // 变更方位及其修改方法映射
        const doFn = {
          top, //上
          bottom, //下
          left, //左
          right, //右
          topright: () => {
            top();
            right();
          }, //右上
          topleft: () => {
            top();
            left();
          }, //左上
          bottomleft: () => {
            bottom();
            left();
          }, //左下
          bottomright: () => {
            bottom();
            right();
          } //右下
        };
        doFn[pos.dir]();
      };
      //鼠标按下 触发变更事件
      el.onmousedown = (e: any) => {
        if (e.target.name !== "resize") return;
        let d = getDirection(e);
        //当位置为四个边和四个角才开启尺寸修改
        if (mouseDir[d]) {
          pos.width = el.clientWidth;
          pos.height = el.clientHeight;
          pos.top = el.offsetTop;
          pos.left = el.offsetLeft;
          pos.x = e.pageX;
          pos.y = e.pageY;
          pos.dir = d;
          document.onmousemove = changeSize;
        }
        document.onmouseup = resetData;
      };

      /** 鼠标样式变更 */
      const changeShowCursor = throttle((e: any) => {
        e.preventDefault();
        el.style.cursor = "default"; //先恢复鼠标默认
        if (e.target.name !== "resize") return;
        // 修改鼠标显示效果
        let d = getDirection(e);
        // 确定是某个方位的动向
        el.style.cursor = mouseDir[d] || "default";
      }, 200); //节流0.2s
      el.onmousemove = changeShowCursor; //监听根元素上移动的鼠标事件
    }
  }
};

export default (app: App) => {
  //批量注册指令
  Object.entries(directives).forEach(([key, fn]) => {
    app.directive(key, fn);
  });
};

上面的两个指令,主要都是获取元素本身,使用原生的js方法对元素进行操作,需要注意的是v-drag是绑定在根元素的第一个子元素上(调整父元素的位置),而v-resize则是绑定元素本身(调整元素本身的大小)。完成两个指令的编写后,可以在局部引用注册或是全局注册,这里我使用全局注册的方法。

//main.ts 全局注册
import { createApp } from "vue";
import App from "./App.vue";
import registerDirectives from "@/directives";
const app = createApp(App);
registerDirectives(app);
app.mount("#app");

全局注册指令完成后,就可以在组件内使用这两个指令了,接下来我们编写一个比较通用的弹窗组件,可以打开关闭,并且能够拖动和尺寸调整。

四、通用组件封装

这里封装组件的过程和Vue2差别不大,只是组件的编写采用Vue3的组合式API写法,其他方面基本都差不多,对于vue的css过渡效果2和3的版本有些许差异,这里请自行查阅Vue3文档,剩下就是定义一些需要修改的属性,使用props接收,并且设置默认值,尽量让组件可以更方便的自定义修改和扩展。

下面是使用两个指令后,封装的一个弹窗组件,这里面在设置窗体css样式drag-dialog的时候使用了min-width: 200px;min-height: 200px;max-width: 100vw;max-height: 100vh;在这里通过对宽高的限制,就可以不用通过js来限制窗体的大小调整了,之前在写v-resize指令的时候有提到过,使用js来控制显示窗体的最小和最大显示范围,这里个人觉得还是通过css编写方便一些。

<template>
  <transition name="drag-win">
    <div
      class="drag-dialog ban-select-font"
      ref="dragWin"
      v-show="props.modelValue"
      v-resize="props.resizeAble"
    >
      <!-- 拖拽窗体头部 -->
      <div class="drag-bar" :style="props.headStyle" v-drag="props.dragAble">
        <slot name="head" />
        <div
          class="drag-btn drag-close"
          @click="controlDialog"
          v-if="props.closeShow"
        />
        <i
          class="drag-btn drag-full"
          @click="fullScreen"
          v-if="props.fullShow"
        />
      </div>
      <!-- 拖拽框主要部分 -->
      <div class="drag-main" :style="props.mainStyle">
        <slot />
      </div>
    </div>
  </transition>
</template>

<script lang="ts" setup>
import { ref } from "vue";

// props传入数据类型约束
interface Props {
  modelValue: boolean; //控制窗体的显示与否
  width?: string; // 默认宽 —— 设置头高 宽高最好传入变量
  height?: string; // 默认高
  headHeight?: string; // 默认控制栏高
  headStyle?: string; // 控制栏样式
  mainStyle?: string; //主要内容区域样式
  resizeAble?: boolean | string; // 是否可以调整尺寸 默认可以调整
  dragAble?: boolean | string; // 是否可以拖拽 默认可拖拽
  closeShow?: boolean; // 关闭控制显示 默认不显示
  fullShow?: boolean; // 全屏控制显示 默认不显示
}
/** 组件调整参数默认值 */
const props = withDefaults(defineProps<Props>(), {
  modelValue: true,
  width: "500px",
  height: "60vh",
  headHeight: "35px",
  headStyle: "",
  mainStyle: "",
  resizeAble: "",
  dragAble: "",
  closeShow: false,
  fullShow: false
});

// 窗体记录数据类型约束
interface recordType {
  width: number;
  height: number;
  top: number;
  left: number;
  fill: boolean;
}
//记录原来的大小
const recordBox: recordType = {
  width: 0,
  height: 0,
  top: 0,
  left: 0,
  fill: false
};

//获取窗口实体
const dragWin: any = ref(null);
// 事件定义
const emits = defineEmits(["update:modelValue"]);

/** 方法定义 */
// 内部控制窗口开关
const controlDialog = () => {
  emits("update:modelValue", !props.modelValue);
};

// 全屏控件
const fullScreen = () => {
  const tmp = dragWin.value;
  const style = dragWin.value.style;
  // 宽的样式 如果被手动缩小或者放大,则表示非全屏状态,则将状态置为false
  if (!style.width || style.width !== "100vw") {
    recordBox.fill = false;
  }
  // 全屏或是还原
  if (recordBox.fill) {
    style.width = `${recordBox.width}px`;
    style.height = `${recordBox.height}px`;
    style.top = `${recordBox.top}px`;
    style.left = `${recordBox.left}px`;
  } else {
    // 记录一下原来的样式
    recordBox.width = tmp.offsetWidth;
    recordBox.height = tmp.offsetHeight;
    recordBox.top = tmp.offsetTop;
    recordBox.left = tmp.offsetLeft;
    //全屏样式
    style.width = "100vw";
    style.height = "100vh";
    style.top = "0px";
    style.left = "0px";
  }
  recordBox.fill = !recordBox.fill; // 全屏状态变换
};
</script>

<style scoped>
 /* 禁止选中文字 */
.ban-select-font {
  -moz-user-select: none; /*火狐*/
  -webkit-user-select: none; /*webkit浏览器*/
  -ms-user-select: none; /*IE10*/
  -khtml-user-select: none; /*早期浏览器*/
  user-select: none;
}

.drag-dialog {
  position: fixed;
  width: v-bind("props.width");
  height: v-bind("props.height");
  left: calc(50% - v-bind("props.width") / 2);
  top: calc(50% - v-bind("props.height") / 2);
  box-sizing: border-box;
  padding: 8px;
  overflow: hidden;
  color: #fff;
  min-width: 200px;
  min-height: 200px;
  max-width: 100vw;
  max-height: 100vh;
  background-color: #313438cc;
}

.drag-bar {
  width: 100%;
  cursor: move;
  height: v-bind("props.headHeight");
  border-bottom: 1px solid #fff;
  box-sizing: border-box;
  padding: 1px 2px 9px;
}

.drag-btn {
  width: 25px;
  height: 25px;
  float: right;
  cursor: pointer;
  margin-left: 5px;
  border-radius: 50%;
}

.drag-full {
  background-color: #28c940b8;
}

.drag-full:hover {
  background-color: #28c93f;
}

.drag-close {
  background-color: #f2473ec7;
}

.drag-close:hover {
  background-color: #f2473e;
}

.drag-main {
  width: 100%;
  height: calc(100% - v-bind("props.headHeight"));
  box-sizing: border-box;
  overflow: auto;
  font-size: 13px;
  line-height: 1.6;
}

/* vue渐入渐出样式 */
.drag-win-enter-from,
.drag-win-leave-to {
  opacity: 0;
  transform: scale(0);
}
.drag-win-enter-to,
.drag-win-leave-from {
  opacity: 1;
}
.drag-win-enter-active,
.drag-win-leave-active {
  transition: all 0.5s ease;
}
</style>

这个组件编写还是有一些问题的,比如打开关闭的时候如果设置过top、left属性,就会变回初始化时候定义的位置,这里可以参考放大缩小记录一下窗口的位置等属性,做一个关闭打开窗体的记录,我这里没有写相关的代码,主要是对我这个项目影响不大,所以有需要的同学可以自己尝试一下怎么编写(ps:主要还是懒)。

编写完组件后就可以引用注册,可以全局或局部注册,这里我使用局部引用注册,然后编写了两个小例子,来使用封装好的组件,可以查看组件封装的props,通过里面的属性来进行组件定制化配置,增减所需功能,然后这里有两个style,一个是头部的样式headStyle,一个是主体样式mainStyle,最外层样式直接在引用时编写style调整即可,然后窗体宽高最好通过传入字符串变量的方式,因为这里还涉及窗体所在容器内的具体位置计算,默认是水平垂直都居中。下面是引用代码:

<template>
  <div>示例演示:</div>
  <button @click="control">{{ btnName }}</button>
  <button @click="box = !box">box控制</button>
  <IsDragDialog v-model="show" closeShow fullShow>
    <template #head>我是头</template>
    <div>我是内容区域</div>
  </IsDragDialog>
  <!-- 关闭某些选项 -->
  <IsDragDialog
    style="top: 200px; left: 10px"
    v-model="box"
    :resize-able="false"
    drag-able
    closeShow
    fullShow
    width="100px"
    height="100px"
  />
</template>

<script lang="ts" setup>
import IsDragDialog from "@/components/IsDragDialog.vue"; //因为使用的是 script setup 这里组件会直接注册
import { computed } from "@vue/reactivity";
import { ref } from "vue";

const show = ref(true);
const box = ref(true);
const control = () => {
  show.value = !show.value;
};

const btnName = computed(() => {
  return show.value ? `关闭窗口` : `打开窗口`;
});
</script>

五、总结及其源代码参考

功能实现主要还是对于dom元素自带的属性需要熟悉掌握,然后通过js的监听事件进行组合事件触发,修改位置,调整dom元素的大小等等,通过一系列的变量参数修改与记录,来实现拖动和dom元素拖拽调整的功能。博文中的代码可能还不够全面,所以我将这个代码抽离然后写了个demo,基于vue/cli搭了个VUe3+TS的小例子,可以在gitee上下载,下面是源码地址,npm i然后npm run sreve就可以查看组件demo了,其实这个组件还可以打包成npm包,但是精力有限,而且这个组件兼容性可能会有问题,所以等以后有机会再做个npm包吧。各位大佬,如果有什么更好的想法欢迎分享,也可以指出本文不足或错误之处,欢迎指正批评。

源代码地址:gitee.com/zero-dg/dra…

六、博文参考

www.runoob.com/jsref/prop-…

https://www.jb51.net/article/245780.htm

到此这篇关于Vue3模仿Windows窗口的文章就介绍到这了,更多相关Vue3模仿Windows窗口内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 教你利用Vue3模仿Windows窗口

    目录 一.前言 二.功能分析 三.指令封装 四.通用组件封装 五.总结及其源代码参考 六.博文参考 一.前言 Vue3终于在2022年2月7日正式发布了,之前用vite+vue3搭了一个小demo,资料太少而我太菜了,所以一直不敢用Vue3搭新项目,现在随着Vue3正式版本的发布,而且相关配合的子项目库也已经完善,大量的翻译资料和文献都已经可以百度到了,再加上领导支持用Vue3新框架,所以我在新项目上着手用vue-cli(@vue/cli 4.5.9)脚手架搭建Vue3项目. 图1 拖拽窗体效果

  • 利用Python实现Windows定时关机功能

    是最初的几个爬虫,让我认识了Python这个新朋友,虽然才刚认识了几天,但感觉有种莫名的默契感.每当在别的地方找不到思路,总能在Python找到解决的办法.自动关机,在平时下载大文件,以及跑程序的时候能用到的,刚才写了个windows自动关机的小程序,程序过于简单,就当是玩玩吧,当然还有很多可改进的地方.下面正文:  #ui制作: 照旧,笔者由Qt制作完成需要的ui,包括label,label_2,label_3,lable_4,lineEdit,lineEdit_2,pushButton组件.

  • 利用Python实现Windows下的鼠标键盘模拟的实例代码

    本文介绍了利用Python实现Windows下的鼠标键盘模拟的实例代码,分享给大家 本来用按键精灵是可以实现我的需求,而且更简单,但既然学python ,就看一下呗. 依赖: PyUserInput pip install PyUserInput PyUserInput 依赖 pyhook,所以还得安装 pyhook.按需下载,下载地址. 我是 win10 64 位 python 2.7,用的是第二个,下载之后用解压软件打开,把 pyHook放到C:\Python27\Lib\site-pack

  • Windows窗口消息实例详解

    本文实例总结了Windows窗口消息.分享给大家供大家参考.具体如下: 复制代码 代码如下: //////////////////////////////////////////////////////////////////////////    #include "AFXPRIV.H"//消息值的定义来源    #include "Dde.h"//DDE消息值的定义来源    #include "CPL.H"//控制面板消息值的定义来源   

  • Python爬虫之教你利用Scrapy爬取图片

    Scrapy下载图片项目介绍 Scrapy是一个适用爬取网站数据.提取结构性数据的应用程序框架,它可以通过定制化的修改来满足不同的爬虫需求. 使用Scrapy下载图片 项目创建 首先在终端创建项目 # win4000为项目名 $ scrapy startproject win4000 该命令将创建下述项目目录. 项目预览 查看项目目录 win4000 win4000 spiders __init__.py __init__.py items.py middlewares.py pipelines

  • 教你利用Python+Turtle绘制简易版爱心表白

    一.效果 快放10倍 总共分为三部分,左上角的正文,下方的心形和右下角的署名 特别需要注意的一点是这种东西不但要装Python,还与分辨率有关(换个屏幕可能效果雪崩,因为用的是绝对坐标),因此并不建议实际拿去弄(哪怕能解决上述两个问题) 二.正文部分 效果: 本质是每写一行话,然后将坐标下移换行,再写一行,以此类推 # content就是该行的内容了,想些啥写啥吧 def drawLine(content, x, y, sleep=3): goto(x, y) write(content, fo

  • 教你利用Selenium+python自动化来解决pip使用异常

    一.pip异常 有一小部分童鞋在打开cmd输入pip后出现下面情况:Did not provide a command Did not provide a command?这是什么鬼? 正常情况应该是酱紫 二.解决办法 1.pip是一个.exe的可执行文件,在cmd输入pip.exe就可以解决了 2.所以在后面的安装指令中都需要带上后缀,那么问题来了,为什么会出现这种情况,如何彻底解决? 三.配置环境变量 1.主要原因是环境变量的PATHEXT里面缺少.EXE的文件名 2.在PATHEXT下编辑

  • 手摸手教你实现Vue3 Reactivity

    目录 前言 开始 小小思考 代码实现 模仿 实现track 实现trigger 实现observe 实现computed 前言 Vue3的响应式基于Proxy,对比Vue2中使用的Object.definedProperty的方式,使用Proxy在新增的对象以及数组的拦截上都有很好的支持. Vue3的响应式是一个独立的系统,可以抽离出来使用,那他到底是如何实现的呢? 都知道有Getter和Setter,那Getter和Setter中分别都进行了哪些主要操作才能实现响应式呢? 哼哼,带着这些问题一

  • 教你编写bat脚本Windows批处理

    目录 常见用途 bat命令速查 常用参数 echo 注释 Rem 使用::声明 dir :获取目录内容 > :将输出重定向到文件 变量 命令行参数 set命令 字符串 数值 局部变量 vs 全局变量 环境变量输出 字符串 创建 空字符串 字符串拼接 字符串长度 转int 截取 右对齐 删除字符串 删除两端(保留中间) 删除空格:= 替换 数组 创建 访问 修改 迭代 数组长度 结构体 if语句 if defined :变量是否存在 if exists:文件是否存在 if errorlevel:测

  • 利用WPF实现Windows屏保的制作

    目录 介绍 正文 实现代码 介绍 框架使用.NET452: Visual Studio 2019; 项目使用 MIT 开源许可协议: 更多效果可以通过GitHub[1]|码云[2]下载代码; 也可以自行添加天气信息等. 正文 屏保程序的本质上就是一个Win32 窗口应用程序: 把编译好一个窗口应用程序之后,把扩展名更改为 scr,于是你的屏幕保护程序就做好了; 选中修改好的 scr 程序上点击右键,可以看到一个 安装 选项,点击之后就安装了; 安装之后会立即看到我们的屏幕保护程序已经运行起来了;

随机推荐