当前位置: 首页 > news >正文

免费网页源代码网站/营销技巧培训

免费网页源代码网站,营销技巧培训,合作行业网站建设,石家庄建设网站引言 大家如果使用过移动端组件库(比如:Vant),会发现在网站右侧有一个手机端的预览效果。 而且这个手机端预览的内容和外面的组件代码演示是同步的,切换组件的时候,移动端预览的内容也会发生相应的变化。 …

引言

大家如果使用过移动端组件库(比如:Vant),会发现在网站右侧有一个手机端的预览效果。

image.png

而且这个手机端预览的内容和外面的组件代码演示是同步的,切换组件的时候,移动端预览的内容也会发生相应的变化。

这是怎么实现的呢?我们一起来看看Vue DevUI组件库的实践吧!

先看下最终实现的效果动画:

移动端预览效果动画1.gif

1 方案选型

通过对竞品进行分析,发现移动端预览都是由嵌入的iframe完成的,也就是说

移动端预览是一个完整的网站。

既然要做一个完整网站,在现有工程结构下想到了以下方案:

1.1 最初的设想

当前文档是通过vitepress搭建的,并且vitepress提供了定制主题的功能,开发完成的组件可以直接在md文档中展示效果,所以就想到通过在vitepress下新建一个mobile路由来包含移动端预览所需的页面。

这会有一个问题,移动端预览页面不需要顶部导航栏和左侧菜单栏,调研发现,vitepress仅支持定制一种主题,虽然貌似可以通过判断路由的方式在模板里面隐藏顶部导航栏和左侧菜单栏的方案(未验证是否可行),但是考虑到md毕竟是来写文档的,虽然可以简单的展示组件效果,但是要做一些复杂的功能(比如目前需要的预览页面首页组件列表),在md文档里面完成可能就不太合适了。

甚至如果以后要做的功能太复杂而无法在md文档里面完成,那么当前的设计就面临着推倒重做的风险。

故排除此方案。

1.2 另一种更好的方案

最好是新起一个移动端预览的工程,并且技术栈与组件库保持一致vue3+vite

这样的话,组件效果可以在新工程里面直接预览,并且这种建站方案成熟,可以做很多事情,即使以后需要做比较复杂的演示效果也不会有大问题。

故采用此方案。

2 移动端工程搭建

2.1 新工程单独出来还是整合到组件库里面?

考虑到组件库应该是一个整体的工程,无论是组件开发、文档输出还是效果预览都应该在一个工程下,如果将移动端预览这部分单独到一个工程里面,会造成维护上的困难。那如何将移动端预览整合到组件库的工程里面呢?

通过在根目录新建mobile文件夹,用来存放移动端预览工程相关的文件,根据vite的配置,还需要新建一个mobile.html入口文件,并在文件里面添加

<script type="module" src="/mobile/main.ts"></script>

开发环境下,可以通过

yarn run app:dev

启动,但是vite默认将index.html文件作为入口,所以在访问路径中增加/mobile.html可以访问移动端预览的页面,完整访问路径为:http://localhost:3001/mobile.html#/button

2.2 路由方式优化

当前组件库工程里面已包含业务场景的工程,采用的history路由,如果移动端预览也采用history路由,在开发阶段会和业务场景冲突,故移动端预览采用的hash路由。

2.3 打包优化

根据vite多页面应用模式的配置,最初将业务场景的代码和移动端预览的代码打包到一起了,后面考虑到两个工程的代码会有分开部署的需求,故对打包配置做了调整,调整后如下:

// vite.config.ts 
// 业务场景代码的配置文件,修改输出目录即可
export default defineConfig({// 其他配置...build: {outDir: 'dist-src'}
})
// 根目录新建vite.config.mobile.ts
// 移动端预览配置文件,指定打包入口和输出目录
export default defineConfig({// 其他配置...build: {outDir: 'dist-mobile',rollupOptions: {input: {mobile: path.resolve(__dirname, 'mobile.html')}}}
})

3 父子页面路由同步

3.1 场景

工程搭建方面的配置基本完成,接下来就需要考虑具体功能实现了。

目前官网(后面用父页面来表示)通过vitepress能够正常访问,移动端预览(后面用子页面来表示)通过vue3+vite的建站方案也能够正常访问。

那两个网站的路由状态如何保持一致呢?

即需要满足以下几个场景:

  • 点击父页面的菜单,子页面路由需要相应修改
  • 点击子页面的菜单,父页面路由需要相应修改
  • 点击浏览器前进和后退按钮,父子页面路由需要同步修改
  • 点击子页面的返回按钮,父子页面路由需要同步修改

3.2 父子页面通信

由于我们采用的是iframe的方案,所以此功能就涉及到iframe父子传参通信,通信方式分为两种:同域跨域

简而言之,同域通信就是通过访问到对应域的window对象,然后进行相应的操作。

跨域通信就是通过postMessage的能力进行消息同步。

同域存在以下两个问题:

  • 由于本地开发,两个工程分别启动在两个端口下面,无法实现同域通信。
  • 同域通过window.location去修改路由,会存在刷新页面的情况,而iframe标签上的src地址是在父页面渲染时去初始化的,如果刷新页面会再次初始化iframe标签上的src地址。而我们想要实现的效果是,只在父页面渲染的时候初始化一次iframe标签上的src地址,后续的操作,iframe标签上的src地址不再变化,只是内部路由变化。

故同域通信的方案被排除。

接下来就是跨域通信的方案了~

因为我们的需求是父子页面路由状态双向同步,所以在父子页面均需要发送消息和接受消息。

父页面通过watch监听在路由变化时,发送消息,代码如下:

// 父页面发送消息
watch(() => route.path,(newPath) => {// 根路由,path为'/';其他路由,为'/component/xxx/'const pathArr = newPath?.split('/');const oFrame = document.querySelector('iframe');oFrame?.contentWindow?.postMessage({type: 'devui',value: newPath === '/' ? '/' : pathArr[pathArr.length - 2],},'*',);},
);

父页面接受消息代码如下:

// 父页面接受消息
window.addEventListener('message', function (event) {if (event.data.type && event.data.type === 'devui') {router.go(event.data.value ? `/components/${event.data.value}/` : '/');}
});

子页面同样在路由变化时发送消息:

watch(router.currentRoute, (newPath) => {// 路由变更来源分为两种:// parent---由父页面影响,包括父页面路由变更,预览页面同步切换;页面首次渲染。触发watch// ''-------点击子页面首页的菜单时,触发watch// 值为parent的情况为父页面影响预览页面,无需再次通过postMessage通信const routeChangeFromParent =sessionStorage.getItem('routeChangeFromParent') === 'parent';if (routeChangeFromParent) {sessionStorage.setItem('routeChangeFromParent', '');return;}window.parent.postMessage({type: 'devui',value: getLinkUrl(newPath.path),},'*',);
});

子页面接受消息代码如下:

window.addEventListener('message', (event) => {if (event.data.type && event.data.type === 'devui') {sessionStorage.setItem('routeChangeFromParent', 'parent');router.replace(event.data.value);}
});

子页面返回上一页面的实现:

点击返回按钮,需要执行浏览器的返回操作,即history.back()。此时父页面的watch监听到路由变化,然后通知子页面变更路由。

3.3 遇到的问题

一、路由变更死循环

由于子页面路由变化来源有两种:父页面通知和点击子页面菜单,为了避免死循环:子通知父变更,父变更之后,再次通知子变更,子又通知父变更…,通过sessionStorage做了标记进行判断拦截。

二、页面显示不出来

mobile-preview-blank-page.png

这个问题出现在页面渲染的时候。

三、选中页面文本,页面错乱

mobile-preview-error-page.png

这个问题出现在选中页面文本的时候。

通过对第二三个问题的分析,发现是message事件被“意外”触发,定位之后发现是因为某些Chrome插件(Augury和沙拉查词)触发了message事件,所以增加了devui的标志,对message事件来源进行过滤。

4 子页面生成

组件库支持PC端和Mobile端组件,在编写文档的时候,演示demo写入了文档中。

增加移动端预览的功能之后,预览框中也需要演示demo,并且演示demo需要和文档中的保持一致。

这时就需要维护两份演示demo。

为了降低后期维护的工作量,就想到了通过自动化脚本的方式,从Markdown文档中提取演示demo代码,然后再输出到移动端预览工程中。

自动化脚本需要支持单个组件和全部组件转换,输入all表示全部转换。

整个自动化脚本大概分为以下几步:

4.1 如何获知要转换哪个组件?

通过命令行的方式,输入命令之后,提示想要转换的组件名称,组件名称需要和组件文件夹名字保持一致,用来从指定文件夹下提取文档内容。

命令交互实现如下:

// mobile-cli-index.js
// 通过commander创建命令
#!/usr/bin/env node
const { Command } = require('commander');
const { create } = require('./generate-mobile-demo');
const { version } = require('../package.json');const program = new Command();program.command('create').description('从md提取演示demo代码,自动输出到mobile文件夹').action(create);program.parse().version(version);
// mobile-inquirers.js
// 通过inquirer提供交互操作
exports.inputComponentName = () => ({name: 'name',type: 'input',message:'(必填)请输入组件名字,将该组件md中的演示代码提取到mobile中,仅支持mobile组件,all表示转换所有Mobile组件:',validate: (value) => {if (value.trim() === '') {return '组件 name 是必填项';}return true;},
});
// generate-mobile-demo.js
// 提供输入命令之后要执行的操作
const inquirer = require('inquirer');
const { inputComponentName } = require('./mobile-inquirers');exports.create = async () => {const { name } = await inquirer.prompt([inputComponentName()]);if (!validateComponentName(name.toLocaleLowerCase())) {console.log('该组件不支持Mobile');process.exit(0);}if (name === 'all') {// 通过遍历的方式,对所有Mobile组件进行转换mobileComponents.forEach((value, key) => {reset();generateSingleComponent(value, key);});} else {// 单个组件转换generateSingleComponent(mobileComponents.get(name), name);}
};

4.2 提取Markdown内容

通过node的能力读取文档内容,实现如下:

const mdFileContent = fs.readFileSync(path.resolve(__dirname, `../docs/components/${componentName}/index.md`),'utf8',
);

4.3 如何从Markdown内容中提取想要的信息?

目前想到两种方案可以实现:

  • 一种是用正则对字符串进行切割;
  • 另一种方案是将Markdown文档转成AST结构,对AST进行遍历,获取到想要的数据。

AST转换更加准确严谨,具备清晰的结构化信息,更加灵活;

而正则表达式需要考虑太多边界情况,无法有效分析上下文。

故采取AST的方案。

借用@textlint/markdown-to-ast插件将Markdown文档转成AST的结构:

const mdParser = require('@textlint/markdown-to-ast').parse;
const mdAST = mdParser(mdFileContent);

AST的结构如下(只截图了部分):

markdown-ast.PNG

通过对AST遍历提取代码,约定好文档中的stylescript、三级标题及其后面紧跟的html或者CodeBlock为我们需要的数据。具体提取过程如下:

mdAST.children.forEach(({ type, depth, lang, raw }) => {if (STYLE_REG.test(raw)) {styleStr = raw;} else if (SCRIPT_REG.test(raw)) {scriptStr = raw;} else if (type === 'Header' && depth === 3) {needPickHtml = true;let title = raw.replace('### ', '');isFlow? (htmlStr += `<div class="demo-block__title">${title}</div>`): tabTitleArr.push(title);} else if (isPureMobile) {if (needPickHtml && type === 'CodeBlock' && lang && lang === 'html') {let content = raw.replace('```html', '').replace('```', '');isFlow ? (htmlStr += content) : tabContentArr.push(content);needPickHtml = false;}} else {if (needPickHtml && type === 'Html') {isFlow ? (htmlStr += raw) : tabContentArr.push(raw);needPickHtml = false;}}
});
  • 通过STYLE_REGSCRIPT_REG识别到Markdown文档中的stylescript代码。
  • 识别三级标题,作为演示demo中的分类标题。
  • 因纯Mobile组件,演示demo不方便直接在文档中展示,故提取type === CodeBlock的代码。
  • 因支持PCMobile的组件,CodeBlock中的代码在预览框中不一定能正常展示,故提取type === html的代码。

4.4 拼接输出字符串

完成htmlstylescript代码提取之后,接下来就是拼接字符串。

字符串的拼接有三种情况:

  • 一种是Markdown文档中没有script代码,这种输出的代码里面需要写好script代码;
  • 第二种是有script代码的情况,这种需要把htmlstylescript的代码都拼接进去;
  • 第三种是输出的Mobile不是流式布局(参考预览框的Button组件),而是Tab结构的布局(参考预览框的PullRefresh组件),这种需要对拼接的字符串做处理。

具体拼接不做过多介绍,下面只展示第二种情况的代码:

function createTemplate() {return `${scriptStr}<template><div class="component-content">${htmlStr}</div></template>${styleStr}`
}

字符串拼接完成之后,就是通过node的能力输出到文件中。这个比较简单,不做过多描述了,直接贴代码:

let fileStr = createTemplate()
fs.outputFile(path.resolve(componentDir, 'index.vue'), fileStr, 'utf8');

4.5 移动端预览首页和路由表生成

移动端预览首页同样是自动生成的,因文档左侧的菜单栏是根据docs/.vitepress/config/sidebar.ts文件中的配置生成的,所以移动端预览首页也是读取的此文件中的配置生成的,只不过需要做个过滤,只渲染Mobile组件。

移动端预览工程的路由表同样也是通过读取docs/.vitepress/config/sidebar.ts文件中的配置生成的,通过拼接字符串的形式输出到mobile/route/index.ts文件中。

5 小结

移动端预览是一个完整的网站,通过iframe的方式嵌入到组件库官网中,然后通过postMessage的能力实现父子页面路由同步。

预览页面通过生成AST的方式,从Markdown文档中提取演示代码自动生成,移动端预览的首页和路由表也同样根据组件库的菜单栏配置文件自动生成。

这样就只需要在Markdown文档中维护菜单栏和演示代码即可,降低维护的工作量。

相关文章:

Vue组件库移动端预览实现原理

引言 大家如果使用过移动端组件库&#xff08;比如&#xff1a;Vant&#xff09;&#xff0c;会发现在网站右侧有一个手机端的预览效果。 而且这个手机端预览的内容和外面的组件代码演示是同步的&#xff0c;切换组件的时候&#xff0c;移动端预览的内容也会发生相应的变化。 …...

FastAPI(七十五)实战开发《在线课程学习系统》接口开发-- 创建课程

源码见&#xff1a;"fastapi_study_road-learning_system_online_courses: fastapi框架实战之--在线课程学习系统" 上次我们分享了&#xff0c;FastAPI&#xff08;七十四&#xff09;实战开发《在线课程学习系统》接口开发-- 删除留言 从本篇文章开始&#xff0c;…...

【C++】 条件变量实现线程同步示例

在做一些比较大的项目的时候&#xff0c;需要实现线程同步&#xff0c; 这里结合一个小示例&#xff0c;进行线程同步的讲解 问题定义 以下是一个使用 C 多线程和条件变量的示例&#xff0c;展示了线程 A 接收一个 enable 信号并通知线程 B 开始工作。线程 B 在开始工作之前…...

linux下载redis安装并指定配置文件启动

linux下载redis并安装启动&#xff1a; cd /usr/local/src 下载redis压缩包 wget http://download.redis.io/releases/redis-6.2.6.tar.gz 解压 tar -xzf redis-6.2.6.tar.gz 编译和安装redis make make install 安装完成后进入 redis 安装目录 cd /usr/local/bin 修改…...

线性结构、线性表、顺序表、链表、头插法、尾插法、中间插入或删除一个节点

梳理几个名词&#xff1a; 逻辑地址&#xff1a;就是说是第几个元素。 物理地址&#xff1a;也就是存储地址&#xff0c;在计算机里具体存放的位置。 线性表的存储结构分为&#xff1a; &#xff08;1&#xff09;顺序存储结构&#xff1a;将数据依次存储在连续的整块物理空…...

C# Task.WaitAll 的用法

目录 简介 1.WaitAll(Task[], Int32, CancellationToken) 2.WaitAll(Task[]) 3.WaitAll(Task[], Int32) 4.WaitAll(Task[], CancellationToken) 5.WaitAll(Task[], TimeSpan) 结束 简介 Task.WaitAll 是 C# 中用于并行编程的一个的方法&#xff0c;它属于 System.Threa…...

vue2 前端实现pdf在线预览(无插件版)

toFielDetail()是点击预览的方法&#xff0c;getOfficialFile是获取文件流的接口正常定义即可&#xff1a; export function getOfficialFile(query) {return request({url: /dataAsset/projectassess/getOfficialFile,method: get,params: query,}); } 调用接口的页面需要引用…...

排序XXXXXXXXX

信息学奥赛&#xff5c;常见排序算法总结&#xff08;C&#xff0b;&#xff09; - 腾讯云开发者社区-腾讯云 (tencent.com) https://cloud.tencent.com/developer/news/975232 常用序号层级排序 一、序号 序号Sequence Number&#xff0c;有顺序的号码&#xff0c;如数字序号…...

【文件解析漏洞】实战详解!

漏洞描述&#xff1a; 文件解析漏洞是由于中间件错误的将任意格式的文件解析成网页可执行文件&#xff0c;配合文件上传漏洞进行GetShell的漏洞! IIS解析漏洞&#xff1a; IIS6.X&#xff1a; 方式一:目录解析 在网站下建立文件夹的名字为.asp/.asa 的文件夹&#xff0c;其目…...

【杂谈】学会让你节省三秒钟——Dev-c++的缺省源

【杂谈】学会让你节省三秒钟——Dev-c的缺省源 1.前言2.缺省源的介绍3.注意 1.前言 你是否在为每次写程序都要自己手打一遍框架而感到苦恼&#xff1f;为什么大佬的Dev-C一新建文件就会自动出现程序框架&#xff1f;看完这篇文章&#xff0c;让你也能成为大佬&#xff0c;不用再…...

推荐一款前端滑动验证码插件(Vue、uniapp)

uniapp版本&#xff1a;滑块拼图验证码&#xff0c;有后端&#xff0c;简单几步即可实现&#xff0c;小程序、h5都可以用 - DCloud 插件市场 Vue版本及cdn版本可以查阅文档&#xff1a; 行为验证 | Poster 文档 示例代码&#xff1a; <template><view id"app&…...

【Git】git stash

目录 基本概念参数详解listshowsavepushpop|applydropclearbranch 参考文章 Git的stash命令是一个非常实用的功能&#xff0c;它允许开发者临时保存工作目录和暂存区的更改&#xff0c;以便能够切换到其他分支或进行其他操作&#xff0c;而不会丢失当前的修改。以下是git stash…...

不得不安利的程序员开发神器,太赞了!!

作为一名程序员&#xff0c;你是否常常为繁琐的后端服务而感到头疼&#xff1f;是否希望有一种工具可以帮你简化开发流程&#xff0c;让你专注于创意和功能开发&#xff1f;今天&#xff0c;我要向大家隆重推荐一款绝佳的开发神器——MemFire Cloud。它专为懒人开发者准备&…...

吴恩达机器学习C1W2Lab06-使用Scikit-Learn进行线性回归

前言 有一个开源的、商业上可用的机器学习工具包&#xff0c;叫做scikit-learn。这个工具包包含了你将在本课程中使用的许多算法的实现。 目标 在本实验室你可以&#xff1a; 利用scikit-learn实现基于正态方程的近似解线性回归 工具 您将使用scikit-learn中的函数以及ma…...

CSS实现表格无限轮播

<div className{styles.tableTh}><div className{styles.thItem} style{{ width: 40% }}>报警名称</div><div className{styles.thItem} style{{ width: 35% }}>开始时间</div><div className{styles.thItem} style{{ width: 25% }}>状态&…...

编程小白如何从迷茫走出

针对新生们常常感到的迷茫&#xff0c;以下是如何选择适合自己的编程语言、如何制定有效的学习计划以及如何避免常见的学习陷阱的详细建议&#xff1a; 一、如何选择适合自己的编程语言 明确需求和目标&#xff1a;不同的编程语言有不同的特点和适用场景。例如&#xff0c;Py…...

14 B端产品的运营管理

通过运营找到需求并通过交换价值提供供给&#xff0c;再逐步扩大规模、站稳脚跟&#xff0c;辅助产品在商业竞争中获胜。 B端产品运营框架 1. 打通渠道 目的&#xff1a;触达客户。 环节&#xff1a;文案策划、活动策划→广告渠道推广→线下BD。 线下BD&#xff1a;通过见面…...

STM32_RTOS学习笔记——1(列表与列表项)

总体RTOS笔记目录 一&#xff0c;列表与列表项&#xff08;本文&#xff09; 二&#xff0c;待定 视频参考&#xff1a;B站野火 一&#xff0c;C语言列表概念 列表就是C语言中的链表&#xff0c;链表就如同下面的衣架一样&#xff0c;需要的各种内容可以参考 C语言链表可…...

子网划分案例

划分子网是将一个较大的网络划分为多个较小的子网&#xff0c;以提高网络管理和安全性 子网划分可以更有效地利用 IP 地址空间&#xff0c;并且有助于控制网络流量、提高网络性能和安全性。 子网划分的主要步骤如下&#xff1a; 确定需要划分的子网数量以及每个子网所需的主…...

javaweb_02:Maven

一、引入 在javaweb的开发中&#xff0c;需要使用大量的jar包&#xff0c;我们得手动去导入&#xff0c;而Maven可以自动帮我们导入和配置这个jar包。 二、Maven项目框架管理工具 核心思想&#xff1a;约定大于配置&#xff08;有约束不违反&#xff09;&#xff1a;Maven会…...

19.延迟队列优化

问题 前面所讲的延迟队列有一个不足之处&#xff0c;比如现在有一个需求需要延迟半个小时的消息&#xff0c;那么就只有添加一个新的队列。那就意味着&#xff0c;每新增一个不同时间需求&#xff0c;就会新创建一个队列。 解决方案 应该讲消息的时间不要跟队列绑定&#xf…...

P10477 Subway tree systems 题解,c++ 树相关题目

题目 poj 链接 洛谷链接 n n n 组数据&#xff0c;每组数据给定两个 01 01 01 串&#xff08;长度不超过 3000 3000 3000&#xff09;&#xff0c;意思如下&#xff1a; 对于每一个 0 0 0&#xff0c;代表该节点有一个子节点&#xff0c;并前往该子节点。对于每一个 1 1 …...

18.jdk源码阅读之CopyOnWriteArrayList

1. 写在前面 CopyOnWriteArrayList 是 Java 中的一种线程安全的 List 实现&#xff0c;基于“写时复制”&#xff08;Copy-On-Write&#xff09;机制。下面几个问题大家可以先思考下&#xff0c;在阅读源码的过程中都会解答&#xff1a; CopyOnWriteArrayList 适用于哪些场景…...

美股:AMD展现乐观前景,挑战AI加速器市场霸主

在科技行业的激烈竞争中&#xff0c;AMD公司近期发布了对当前季度收入的乐观预测&#xff0c;显示出其新推出 一、AMD第三季度营收预期超越分析师平均预期 AMD在周二的声明中预计&#xff0c;第三季度营收将达到约67亿美元&#xff0c;这一数字超出了分析师此前平均预期的66.…...

如何提高计算机视觉技术在复杂环境和低光照条件下的物体识别准确率?

要在复杂环境和低光照条件下提高计算机视觉技术的物体识别准确率&#xff0c;可以采取以下几个方法&#xff1a; 数据增强&#xff1a;在训练集中添加各种复杂环境和低光照条件下的图片&#xff0c;通过增加数据的多样性&#xff0c;使算法能够更好地适应各种场景。 预处理&am…...

ubuntu cmake使用自己版本的qt

给一篇文章参考 https://blog.csdn.net/bank_dreamer/article/details/138678909 自己使用的范例 set(Qt5_DIR "/home/peak/Qt5.14.0/5.14.0/gcc_64/lib/cmake/Qt5")# 设置Qt5的安装目录 #set(CMAKE_PREFIX_PATH "/home/peak/Qt5.14.0")find_package(Qt5…...

Python基础知识笔记---保留字

保留字&#xff0c;也称关键字&#xff0c;是指被编程语言内部定义并保留使用的标识符。 一、保留字概览 二、保留字用途 1. False&#xff1a;表示布尔值假。 2. None&#xff1a;表示空值或无值。 3. True&#xff1a;表示布尔值真。 4. not&#xff1a;布尔逻辑操作符…...

Python面试整理-Web开发

在Python中,Web开发可以利用多种强大的框架和库来构建从简单的静态网页到复杂的动态Web应用。以下是几种流行的Python Web开发框架和相关技术的概述: 1. Flask Flask 是一个轻量级的Web应用框架,它非常灵活,适用于小型到中型项目,或作为构建微服务的基础。Flask的核心非常…...

民大食堂用餐小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;商家管理&#xff0c;档口号管理&#xff0c;商家餐品管理&#xff0c;餐品种类管理&#xff0c;购物车管理&#xff0c;订单信息管理 微信端账号功能包括&#xff1a;系统首页&a…...

Linux系统编程(4):消息队列

Linux下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的。 而对Unix发展做出重大贡献的两大主力AT&T的贝尔实验室 以及 BSD&#xff08;加州大学伯克利分校的伯克利软件发布中心&#xff09;&#xff0c; 他们在进程间通信方面的侧重点有所不同&#xff1b; 前…...