微搭低代码AI组件单词消消乐从0到1实践

news2024/12/12 23:14:45

目录

  • 1 为什么要开发单词消消乐
  • 2 需要具备什么功能
  • 3 采用什么技术方案实现
  • 4 逻辑设计
    • 4.1 数据结构设计
    • 4.2 游戏的核心逻辑
    • 4.3 数据设计
  • 5 代码详解
    • 5.1 导入依赖
    • 5.2 定义函数组件
    • 5.3 数据初始化
    • 5.4 状态定义
    • 5.5 打乱解释的逻辑
    • 5.6 定义选择单词的函数
    • 5.7 定义选择解释的函数
    • 5.8 界面渲染
  • 6 如何使用这个代码
  • 总结

周末线上观看了腾讯TVP技术分享交流,产品经理现场演示了使用新的云开发Copilot写一个抽奖的功能。看完后大受启发,于是我也现学现卖,做一个类似的组件。

单词消消乐小游戏教程

1 为什么要开发单词消消乐

在在线英语单词的APP或者小程序中,有很多学习单词的场景。教培机构为了让学员体会到学习的乐趣,通常会引入游戏的元素。那么单词消消乐就是一种趣味性的工具。

低龄孩子在消消乐的过程中,既记住了单词又有耐心把学习进行完毕。

2 需要具备什么功能

  • 屏幕左侧显示一组英文单词,右侧显示一组中文解释。
  • 玩家需要点击英文单词和其对应的中文解释,如果配对正确,单词和解释会从屏幕中消失。
  • 当所有单词和解释都匹配完成后,显示“游戏结束”,并提供重新开始的选项。

3 采用什么技术方案实现

单词消消乐总体算是复杂逻辑了,如果我们使用基本的组件,比如普通容器、文本、按钮这些搭建。不是说不可以,但是问题是要考虑副作用的问题。

微搭总体是使用react组件设计的,简单场景没问题,但是复杂场景,尤其在用户快速点击的时候,就会有奇奇怪怪的问题。比如我的单词明明选中了,要消掉,但是还留着。这种就大大影响用户的体验了。

过去这种我们只能是将就用,但是新版本提供了AI代码块的组件,支持你用React的语法实现自己想要的功能,就比较方便了。

4 逻辑设计

要想设计一款比较好玩的游戏,逻辑是非常重要的,逻辑想明白了,代码只是逻辑的实现罢了。有的人就感觉技术非常高级,技术本身是为业务服务的,企业最终是通过技术来实现自己的商业目标。

TVP的一位嘉宾的观点我非常认同,系统的价值在于给企业带没带来效率的提升,成本的降低,给没给用户的体验带来提升。那我们在做程序设计的时候也需要把用户体验放在首位进行考虑。

4.1 数据结构设计

游戏的核心是管理一组单词和对应的解释,因此我们用数组来存储这些数据。

每个单词和解释用一个对象表示,包含两个属性:

  • word:英文单词。
  • definition:对应的中文解释。

实际的数据结构是长这样的

[
  { word: "apple", definition: "苹果" },
  { word: "banana", definition: "香蕉" }
]

4.2 游戏的核心逻辑

1.初始化游戏:

  • 提供一组单词和解释。
  • 打乱右侧的中文解释顺序,增加挑战性。

2.点击事件:

  • 玩家点击一个英文单词后,再点击一个中文解释。
  • 判断二者是否匹配,匹配成功:将这对单词和解释从屏幕移除。匹配失败:重置选择,提示玩家重新尝试。

3.游戏结束:

  • 当所有单词都匹配完成,显示“重新开始”的按钮。

4.重新开始:

  • 恢复初始状态,重新打乱解释。

4.3 数据设计

我们的组件需要设计一些数据来跟踪用户的点击,我们考虑如下数据

  • pairs:剩余的单词和解释。
  • shuffledDefinitions:打乱后的解释。
  • selectedWord 和 selectedDefinition:当前被选中的单词和解释。
  • matchedPairs:已匹配成功的单词和解释。

5 代码详解

完整代码如下:

import React, { useState, useEffect } from 'react';
import { Button, CardContent, CardTitle } from '@/components/ui';

// 打乱数组顺序的函数
const shuffle = (array) => {
  return array.sort(() => Math.random() - 0.5);
};

export default function WordMatchGame() {
  const initialPairs = $w.page.dataset.state.words

  const [pairs, setPairs] = useState(initialPairs); // 存储单词和解释的数组
  const [shuffledDefinitions, setShuffledDefinitions] = useState([]); // 存储打乱后的中文解释
  const [selectedWord, setSelectedWord] = useState(null); // 当前选中的单词
  const [selectedDefinition, setSelectedDefinition] = useState(null); // 当前选中的解释
  const [matchedPairs, setMatchedPairs] = useState([]); // 匹配成功的单词和解释

  // 打乱解释的顺序
  useEffect(() => {
    const shuffled = shuffle(pairs.map(pair => pair.definition)); // 仅打乱中文解释
    setShuffledDefinitions(shuffled);
  }, [pairs]); // 当 pairs 改变时重新打乱解释

  // 选择单词
  const selectWord = (word) => {
    if (matchedPairs.some(pair => pair.word === word)) return; // 如果该单词已匹配成功,则不能再次选择
    console.log(`选择单词: ${word}`);  // 输出选中的单词
    setSelectedWord(word);
  };

  // 选择解释
  const selectDefinition = (definition) => {
    console.log(`选择解释: ${definition}`);  // 输出选中的解释
    setSelectedDefinition(definition);

    // 找到选中的单词的正确解释
    const correctDefinition = pairs.find(pair => pair.word === selectedWord)?.definition;

    if (correctDefinition && correctDefinition === definition) {
      // 如果匹配成功,消除配对的单词和解释
      console.log('匹配成功!'); // 输出匹配成功的日志
      setMatchedPairs(prev => [...prev, { word: selectedWord, definition }]);
      
      // 移除已匹配的单词和解释
      setPairs(prevPairs =>
        prevPairs.filter(pair => pair.word !== selectedWord && pair.definition !== definition)
      );

      // 重置选中的单词和解释
      setSelectedWord(null);
      setSelectedDefinition(null);
    } else {
      console.log('匹配失败!'); // 输出匹配失败的日志
      // 如果匹配失败,重置选中的单词和解释
      setTimeout(() => {
        setSelectedWord(null);
        setSelectedDefinition(null);
      }, 500); // 延迟恢复,避免闪烁
    }
  };

  // 渲染单词和解释列
  const renderColumn = (column, isWordColumn) => {
    return column.map((item, index) => {
      // 根据是否选中单词来改变样式
      const isSelected = isWordColumn ? selectedWord === item.word : selectedDefinition === item;
      const selectedClass = isSelected ? 'bg-green-300' : '';  // 选中时背景为绿色

      return (
        <div
          key={index}
          className={`cursor-pointer p-2 mb-2 bg-white rounded-lg shadow-md ${isWordColumn ? 'text-left' : 'text-right'} ${selectedClass}`}
          onClick={() => isWordColumn ? selectWord(item.word) : selectDefinition(item)}
        >
          {isWordColumn ? item.word : item}
        </div>
      );
    });
  };

  // 判断是否所有的单词和解释都已匹配成功
  const isGameOver = pairs.length === 0;

  // 重新开始游戏
  const restartGame = () => {
    setPairs(initialPairs); // 重置 pairs 数组
    setMatchedPairs([]); // 清空匹配记录
    setShuffledDefinitions(shuffle(initialPairs.map(pair => pair.definition))); // 重新打乱解释顺序
    setSelectedWord(null); // 清空选中的单词
    setSelectedDefinition(null); // 清空选中的解释
  };

  return (
    <div className="flex flex-col items-center justify-center min-h-screen bg-gradient-to-r from-green-400 via-blue-500 to-purple-500 relative">
      <div className="text-white text-4xl font-extrabold mb-8">单词对对碰游戏</div>

      {/* 游戏列 */}
      <div className="flex justify-center space-x-12">
        <div className="flex flex-col space-y-2">
          <CardTitle className="text-white font-bold text-xl mb-4">英文单词</CardTitle>
          {pairs.map((pair, index) => (
            <div
              key={index}
              className={`cursor-pointer p-2 mb-2 bg-white rounded-lg shadow-md text-left ${selectedWord === pair.word ? 'bg-green-300' : ''}`}
              onClick={() => selectWord(pair.word)}
            >
              {pair.word}
            </div>
          ))}
        </div>
        <div className="flex flex-col space-y-2">
          <CardTitle className="text-white font-bold text-xl mb-4">中文解释</CardTitle>
          {renderColumn(shuffledDefinitions, false)} {/* 渲染打乱后的中文解释列 */}
        </div>
      </div>

      {/* 匹配成功的信息 */}
      {matchedPairs.length > 0 && (
        <div className="mt-6 text-white text-xl">
          <CardContent>
            <CardTitle>已匹配:</CardTitle>
            <ul>
              {matchedPairs.map((pair, index) => (
                <li key={index}>{pair.word} - {pair.definition}</li>
              ))}
            </ul>
          </CardContent>
        </div>
      )}

      {/* 重新开始按钮 */}
      {isGameOver && (
        <Button onClick={restartGame} className="mt-6 bg-green-500 text-white px-6 py-2 rounded-md shadow-lg">
          重新开始
        </Button>
      )}
    </div>
  );
}

5.1 导入依赖

import React, { useState, useEffect } from 'react';
import { Button, CardContent, CardTitle } from '@/components/ui';

一开头,有两条导入语句,这部分相当于是要引入已经封装好的第三方库。

先导入了React框架

  • React 是一个前端框架,用来构建用户界面。
  • 每个 React 组件需要 React 提供的一些功能,比如状态管理(useState)、生命周期管理(useEffect)等。

这个就相当于我们可以直接用方法名调用它封装好的方法,但是也必须要强制符合他的方法定义的要求,不能自由发挥。开源的东西看似好用,其实是引入了复杂性,遇到问题就比较费时间。

之后导入了导入 useState 和 useEffect

  • useState:用来定义和管理组件的状态。
  • useEffect:用来定义组件的副作用逻辑,比如初始化数据、监听事件等。

导入 UI 组件

  • Button、CardContent、CardTitle 是从一个自定义的 UI 库中引入的现成组件,用来实现按钮、卡片标题等界面元素。

5.2 定义函数组件

export default function WordMatchGame() {

这是一个 React 函数组件,在 React 中,所有的界面逻辑都定义在组件里。WordMatchGame 是这个组件的名字,表示这是一个“单词配对游戏”的组件。

export default 的作用:它表示将 WordMatchGame 组件作为模块导出,方便其他地方引入使用。

5.3 数据初始化

const initialPairs = $w.page.dataset.state.words;

这一行是做什么的?

定义了一个变量 initialPairs,它存储了游戏初始的单词和解释配对数据。

数据来源是 $w.page.dataset.state.words,表示从页面的数据集里获取单词和解释。

在JSX组件中是可以引用我们微搭中定义的各种自定义变量的,在代码区我们可以创建一个数组变量,用来初始化数据
在这里插入图片描述
默认值是

[
  {
    "word": "apple",
    "definition": "苹果"
  },
  {
    "word": "dog",
    "definition": "狗"
  },
  {
    "word": "car",
    "definition": "汽车"
  },
  {
    "word": "sun",
    "definition": "太阳"
  },
  {
    "word": "tree",
    "definition": "树"
  },
  {
    "word": "house",
    "definition": "房子"
  }
]

5.4 状态定义

const [pairs, setPairs] = useState(initialPairs);
const [shuffledDefinitions, setShuffledDefinitions] = useState([]);
const [selectedWord, setSelectedWord] = useState(null);
const [selectedDefinition, setSelectedDefinition] = useState(null);
const [matchedPairs, setMatchedPairs] = useState([]);

使用 React 的 useState 定义了 5 个状态,分别是:

  1. pairs:游戏的核心数据(单词和解释配对)。
  2. shuffledDefinitions:打乱后的中文解释,用来显示在界面上。
  3. selectedWord:当前选中的英文单词。
  4. selectedDefinition:当前选中的中文解释。
  5. matchedPairs:匹配成功的单词和解释。

每个状态都有两个变量,pairs 是状态的值;setPairs 是修改状态的函数。

用中括号定义是React强制的语法,React 提供了一个叫做 useState 的 Hook,用来定义和管理组件的状态。

语法说明:

const [状态变量, 修改状态的函数] = useState(初始值);
  • 状态变量:存储数据的地方(如 pairs)。
  • 修改状态的函数:用来更新状态,React 会自动重新渲染界面(如 setPairs)。
  • 初始值:状态的初始数据,比如 initialPairs。

5.5 打乱解释的逻辑

useEffect(() => {
  const shuffled = shuffle(pairs.map(pair => pair.definition));
  setShuffledDefinitions(shuffled);
}, [pairs]);

useEffect 的作用:这个函数在组件渲染后运行。它监听 pairs 的变化,只要 pairs 更新,就会重新执行里面的代码。

具体逻辑:pairs.map(pair => pair.definition) 提取所有中文解释。调用 shuffle 函数打乱解释的顺序。将打乱后的结果保存到状态 shuffledDefinitions。

设计这个的初衷是,如果不把解释打乱,用户就知道你的答案是一一对应的,也就失去了学习的意义。

5.6 定义选择单词的函数

const selectWord = (word) => {
  if (matchedPairs.some(pair => pair.word === word)) return;
  setSelectedWord(word);
};

这段代码是干什么的?

  1. 定义了一个函数 selectWord,用来处理“点击单词”的操作。
  2. 如果这个单词已经匹配成功(在 matchedPairs 里),直接返回。否则,将当前选中的单词存储到 selectedWord 状态。

5.7 定义选择解释的函数

const selectDefinition = (definition) => {
  setSelectedDefinition(definition);

  const correctDefinition = pairs.find(pair => pair.word === selectedWord)?.definition;

  if (correctDefinition && correctDefinition === definition) {
    setMatchedPairs(prev => [...prev, { word: selectedWord, definition }]);
    setPairs(prev => prev.filter(pair => pair.word !== selectedWord));
  } else {
    setTimeout(() => {
      setSelectedWord(null);
      setSelectedDefinition(null);
    }, 500);
  }
};

这段代码是干什么的?

  1. 定义了一个函数 selectDefinition,用来处理“点击解释”的操作。
  2. 将当前选中的解释存储到 selectedDefinition 状态。查找当前选中的单词的正确解释(correctDefinition)。判断是否匹配成功:成功:更新匹配记录,并从未匹配的单词中移除该配对。失败:延迟清空选中的单词和解释。

5.8 界面渲染

return (
    <div className="flex flex-col items-center justify-center min-h-screen bg-gradient-to-r from-green-400 via-blue-500 to-purple-500 relative">
      <div className="text-white text-4xl font-extrabold mb-8">单词对对碰游戏</div>

      {/* 游戏列 */}
      <div className="flex justify-center space-x-12">
        <div className="flex flex-col space-y-2">
          <CardTitle className="text-white font-bold text-xl mb-4">英文单词</CardTitle>
          {pairs.map((pair, index) => (
            <div
              key={index}
              className={`cursor-pointer p-2 mb-2 bg-white rounded-lg shadow-md text-left ${selectedWord === pair.word ? 'bg-green-300' : ''}`}
              onClick={() => selectWord(pair.word)}
            >
              {pair.word}
            </div>
          ))}
        </div>
        <div className="flex flex-col space-y-2">
          <CardTitle className="text-white font-bold text-xl mb-4">中文解释</CardTitle>
          {renderColumn(shuffledDefinitions, false)} {/* 渲染打乱后的中文解释列 */}
        </div>
      </div>

      {/* 匹配成功的信息 */}
      {matchedPairs.length > 0 && (
        <div className="mt-6 text-white text-xl">
          <CardContent>
            <CardTitle>已匹配:</CardTitle>
            <ul>
              {matchedPairs.map((pair, index) => (
                <li key={index}>{pair.word} - {pair.definition}</li>
              ))}
            </ul>
          </CardContent>
        </div>
      )}

      {/* 重新开始按钮 */}
      {isGameOver && (
        <Button onClick={restartGame} className="mt-6 bg-green-500 text-white px-6 py-2 rounded-md shadow-lg">
          重新开始
        </Button>
      )}
    </div>
  );

这里其实就需要懂HTML和CSS了,这里的CSS是引入了Tailwind CSS,我发现微搭的技术栈里这个是可以使用的,用样式库自带的样式搭建界面还是非常快的

这里唯一需要注意的就是{}的使用,他的作用类似于表达式,凡是你要用表达式的就得用{}包裹起来

6 如何使用这个代码

上边代码要想看的懂,需要你学习React、HTML、CSS、JavaScript,学习过程还是比较艰辛的。但是代码的一个最大的特点是可以拷贝粘贴,我们使用我们的cv大法看如何使用。

在应用中创建一个页面
在这里插入图片描述

输入页面的名称
在这里插入图片描述
加入我们的AI代码块组件
在这里插入图片描述
点击编辑JSX代码
在这里插入图片描述
将教程的完整代码贴入编辑器中
在这里插入图片描述
在代码区创建一个数组变量words
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
然后设置默认值

[
  {
    "word": "apple",
    "definition": "苹果"
  },
  {
    "word": "dog",
    "definition": "狗"
  },
  {
    "word": "car",
    "definition": "汽车"
  },
  {
    "word": "sun",
    "definition": "太阳"
  },
  {
    "word": "tree",
    "definition": "树"
  },
  {
    "word": "house",
    "definition": "房子"
  }
]

我们的效果就有了
在这里插入图片描述
点击预览就大功告成啦

总结

我们本篇介绍了微搭的新能力,AI组件的具体用法。结合一个实战案例单词消消乐,详细讲解了游戏的功能设计、逻辑设计以及代码逻辑。对于复杂需求,借助纯代码也是一种可行解。但是纯代码技术难度高,调错复杂,未来也许AI的能力提高之后这部分就不是太复杂的一件事。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

learn-(Uni-app)输入框u-search父子组件与input输入框(防抖与搜索触发)

1.父子组件u-search &#xff08;1&#xff09;父组件 <!-- 父组件 --> <template> <div><searchBar change"change" search"search"></searchBar> </div> </template> <script> // 子组件搜索 import…

SpringBoot【九】mybatis-plus之自定义sql零基础教学!

一、前言&#x1f525; 环境说明&#xff1a;Windows10 Idea2021.3.2 Jdk1.8 SpringBoot 2.3.1.RELEASE mybatis-plus的基本使用&#xff0c;前两期基本讲的差不多&#xff0c;够日常使用&#xff0c;但是有的小伙伴可能就会抱怨了&#xff0c;若是遇到业务逻辑比较复杂的sq…

electron 打包 webview 嵌入需要调用电脑摄像头拍摄失败问题

electron 打包 webview 嵌入需要调用电脑摄像头拍摄失败问题 这篇文章是接我cocos专栏的上一篇文章继续写的&#xff0c;我上一篇文章写的是 cocos 开发触摸屏项目&#xff0c;需要嵌入一个网页用来展示&#xff0c;最后通过 electron 打包成 exe 程序&#xff0c;而且网页里面…

webrtc学习----前端推流拉流,局域网socket版,一对一

提示&#xff1a;局域网socket版 文章目录 [TOC](文章目录) 前言一、教程二、webrtc工作流程三、推流端四、拉流五、socket服务六、效果七、备注总结 前言 ‌‌‌‌‌WebRTC&#xff08;Web Real-Time Communication&#xff09;‌是一种实时通讯技术&#xff0c;允许网络应用或…

net/http: TLS handshake timeout 问题

最近系统偶现”net/http: TLS handshake timeout“&#xff0c;而且都集中在同一个机房&#xff0c;这个报错还是第一次见&#xff0c;产生的原因和解决的方案都比较有意思。 现场 报错的信息为&#xff1a; Error sending request:%!(EXTRA *url.ErrorGet "https://**…

HTML简单贪吃蛇游戏

1.功能说明&#xff1a; 游戏网格&#xff1a;一个20x20的网格&#xff0c;每个格子的大小为20x20像素。 蛇的移动&#xff1a;玩家可以通过方向键&#xff08;左、上、右、下&#xff09;控制蛇的移动。 食物生成&#xff1a;食物会在随机位置生成&#xff0c;当蛇吃到食物时…

http 502 和 504 的区别

首先看一下概念&#xff1a; 502&#xff1a;作为网关或者代理工作的服务器尝试执行请求时&#xff0c;从上游服务器接收到无效的响应。503&#xff1a;由于临时的服务器维护或者过载&#xff0c;服务器当前无法处理请求。这个状况是临时的&#xff0c;并且将在一段时间以后恢…

基于SpringBoot医疗挂号系统(计算机毕业设计)+万字说明文档

系统合集跳转 源码获取链接 一、系统环境 运行环境: 最好是java jdk 1.8&#xff0c;我们在这个平台上运行的。其他版本理论上也可以。 IDE环境&#xff1a; Eclipse,Myeclipse,IDEA或者Spring Tool Suite都可以 tomcat环境&#xff1a; Tomcat 7.x,8.x,9.x版本均可 操作系统…

【青牛科技】D4800 AB类 立 体 声 耳 机 音 频 功 率 放 大器电路可应用在便携式数字 音 响 设 备 中 作 功 率 放 大 用

概 述 &#xff1a; D4800 是 一 块 AB类 立 体 声 耳 机 音 频 功 率 放 大器电路。 D4800 在5V电 源 时 输 出 功 率 最 高 可 达 290mW(8 Ω 负载&#xff0c; 失真度 10%)。适合在便携式数字 音 响 设 备 中 作 功 率 放 大 用 。 主要特点&#xff1a; 电源电压&#x…

vue3+vite接入iconify,支持离线

前言 找一个图标太难了。Element-plus Icon的不够用。阿里巴巴的iconfont又比较麻烦。如果有自己的UI组件也可以考虑。 为了快速开发&#xff0c;我选择unocss iconify。 网上的教程太多了&#xff0c;建议大家直接看文档&#xff0c;其实配置步骤只有几步&#xff0c;不多。…

SD Express 卡漏洞导致笔记本电脑和游戏机遭受内存攻击

Positive Technologies 最近发布的一份报告揭示了一个名为 DaMAgeCard 的新漏洞&#xff0c;攻击者可以利用该漏洞利用 SD Express 内存卡直接访问系统内存。 该漏洞利用了 SD Express 中引入的直接内存访问 (DMA) 功能来加速数据传输速度&#xff0c;但也为对支持该标准的设备…

网页核心页面设计(第8章)

一、伪元素 伪元素是 CSS 中的一种选择器&#xff0c;用于选择某些特定的元素或元素的一部分&#xff0c;而这些元素本身并不存在于文档的结构中。伪元素使得网页设计师可以更灵活地控制样式&#xff0c;从而可以为元素的内容、框架或文本提供额外的样式&#xff0c;增强网页的…

黑马商城微服务复习(5)

MQ 一、同步调用和异步调用1. 同步调用2. 异步调用 二、RabbitMQ1. 基础使用2. 实际操作 怎么用?3. RabbitMQ虚拟主机 数据隔离4. 在JAVA中实现RabbitMQ5. 交换机种类 一、同步调用和异步调用 1. 同步调用 微服务一旦拆分&#xff0c;必然涉及到服务之间的相互调用&#xff…

【MySQL】表的基本查询(上)

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

【Java学习笔记】Map接口和常用方法

一、 Map接口实现类的 特点[很实用] key是自己存的java对象 value是一个固定的 //当有相同的 k ,就等价于替换. 二、 Map常用方法 &#xff08;根据键–>k&#xff09; 三、Map接口遍历方法 package com.hspedu.map_; import java.util.*; /** * author 韩顺平 * ver…

MySQL8版本升级

1.官方升级手册必看 1.1 理解升级过程会做什么 手册网址&#xff1a;https://dev.mysql.com/doc/refman/8.0/en/upgrading.html 升级mysql 系统数据库&#xff08;默认的库&#xff09;&#xff0c;升级mysql 用户数据库&#xff08;用户创建的库&#xff09; 升级步骤分为…

CTFshow-命令执行(Web29-40)

CTFshow-命令执行(Web29-40) CTFWeb-命令执行漏洞过滤的绕过姿势_绕过空格过滤-CSDN博客 总结rce&#xff08;远程代码执行各种sao姿势&#xff09;绕过bypass_远程命令执行绕过-CSDN博客 对比两者的源代码&#xff0c;我们发现&#xff0c;cat指令把flag.php的内容导出后依…

【OpenCV】直方图

理论 可以将直方图视为图形或曲线图&#xff0c;从而使您对图像的强度分布有一个整体的了解。它是在X轴上具有像素值(不总是从0到255的范围)&#xff0c;在Y轴上具有图像中相应像素数的图。 这只是理解图像的另一种方式。通过查看图像的直方图&#xff0c;您可以直观地了解该…

OpenAI直播发布第4天:ChatGPT Canvas全面升级,免费开放!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;专注于分享AI全维度知识&#xff0c;包括但不限于AI科普&#xff0c;AI工…

PDF 文件如何转为 CAD 图纸?PDF2CAD 使用教程

在工程设计和建筑行业中&#xff0c;PDF 文件常常被用来分享和存档图纸。然而&#xff0c;当需要对这些图纸进行编辑或进一步开发时&#xff0c;静态的 PDF 格式就显得力不从心了。这时候&#xff0c;将 PDF 文件转换为可编辑的 CAD&#xff08;计算机辅助设计&#xff09;格式…