提起帮助文档,想必大家都会想到 VuePress等,我也体验了一下,但是感觉和我的思路不太一样,我希望的是那种可以直接在线编辑文档,然后无需编译就可以直接发布的方式,另外可以在线写(修改)代码并且运行的效果。

VuePress 是“静态网站生成器”,需要我们自行编写文档,然后交给VuePress变成网站,VuePress 并没有提供编写环境,我知道有很多编写 Markdown 的方式,但是我还是喜欢编写、浏览合为“一体”的方式。

似乎没有,那么 —— 自己动手丰衣足食吧,开干!

技术栈

  • vite: ^2.7.0
  • vue: ^3.2.23
  • axios: ^0.25.0 获取json格式的配置和文档
  • element-plus: ^2.0.2 UI库
  • nf-ui-elp": ^0.1.0 二次封装的UI库
  • @element-plus/icons-vue: ^0.2.4 图标
  • @kangc/v-md-editor:"^2.3.13 md 编辑器
  • vite-plugin-prismjs: ^0.0.8 代码高亮
  • nf-state": ^0.2.4 状态管理
  • nf-web-storage": ^0.2.3 访问 indexedDB

建立库项目(@naturefw/press-edit)实现文档的编写、浏览功能

首先使用 vite2 建立一个 Vue3 的项目:

  • 安装 elementPlus 实现页面效果;
  • 安装 v-md-editor 实现 Markdown 的编辑和显示;
  • 安装 @naturefw/storage 操作 indexedDB ,实现帮助文档的存储;
  • 安装 @naturefw/nf-state 实现状态管理;
  • 安装axios 用于加载 json文件,实现导入功能。
  • 用node写一个后端API,实现写入json文件的功能。

注意:库项目需要安装以上插件,帮助文档项目只需要安装 @naturefw/press-edit 即可。

基本功能就是这样,心急的可以先看在线演示和源码。

  1. 在线演示:https://nfpress.gitee.io/nf-press-edit/
  2. 源码:https://gitee.com/nfpress/nf-press-edit

两个状态:编辑和浏览

一开始做了两个项目,分别实现编辑文档和显示文档的功能,但是后来发现,内部代码大部分是相同的,维护的时候有点麻烦,所以改为在编辑文档的项目里加入“浏览”的状态,然后设置切换的功能,这样便于内部代码的维护,以后成熟了可能会分为两个单独的项目。

编辑状态的功能

  • 菜单维护
  • 文档维护
  • 文档展示
  • 导入导出
  • 在线编写/执行代码

我喜欢在线编辑的方式,这样更省心,于是我用 el-menu 实现导航和左侧的菜单,然后加上了维护功能。

使用 v-md-editor 实现 Markdown 的编辑和显示。

然后用node写了一个后端API,实现保存 json文件的功能,这样就完美了。

浏览状态的功能

  • 导航
  • 菜单
  • 文档展示
  • 执行代码

就是在编辑状态的功能的基础上,去掉一些功能。或者其实可以反过来思考。

实现导航

首先参考 VuePress 设置一个json文件,用于加载和保存网站信息、导航信息。

/public/docs/.nfpress/project.json

{
"projectId": "1000",
"title": "nf-press-edit !",
"description": "这是一个在线编辑、展示文档的小工具",
"navi": [
{
"naviId": "1010",
"text": "指南",
"link": "menu"
},
{
"naviId": "1020",
"text": "组件",
"link": "menu"
},
{
"naviId": "1380",
"text": "Gitee",
"link": "https://gitee.com/nfpress/nf-press-edit"
},
{
"naviId": "1390",
"text": "在线演示",
"link": "https://nfpress.gitee.io/nf-press-edit/"
},
{
"naviId": "1395",
"text": "我要提意见",
"link": "https://gitee.com/nfpress/nf-press-edit/issues"
}
]
}
  • projectId:项目ID,可以用于区分不同的帮助文档项目。
  • navi: 存放导航项。
  • naviId: 关联到菜单。
  • text: 导航上显示的文字。
  • link: 连接方式或链接地址。menu:表示要打开对应的菜单;URL:在新页面里打开连接。

然后做一个组件,用 el-menu 绑定数据渲染出来即可实现导航效果。

/lib/navi/navi.vue

  <el-menu
:default-active="activeIndex2"
class="el-menu-demo"
mode="horizontal"
v-bind="$attrs"
:background-color="backgroundColor"
@select="handleSelect"
>
<el-menu-item
v-for="(item, index) in naviList"
:key="index"
:index="item.naviId"
>
{{item.text}}
</el-menu-item>
</el-menu>

可以是多级的导航,暂时没有实现在线维护功能。

  import { ref } from 'vue'
import { ElMenu, ElMenuItem } from 'element-plus'
import { state } from '@naturefw/nf-state' const props = defineProps({
'background-color': { // 默认背景色
type: String,
default: '#ece5d9'
},
itemProps: Object
}) // 获取状态和导航内容
const { current, naviList } = state
// 激活第一个导航项
const activeIndex2 = ref(naviList[0].naviId) const handleSelect = (key, keyPath) => {
const navi = naviList.find((item) => item.naviId === key)
if (navi.link === 'menu') {
// 打开菜单
current.naviId = key
} else {
// 打开连接
window.open(navi.link, '_blank')
}
}
  • @naturefw/nf-state

    自己写的一个轻量级状态管理,可以当做大号 reactive 来使用,通过状态管理加载 project.json 然后绑定渲染。

  • naviList

    导航列表,由状态管理加载。

  • current

    当前激活的各种信息,比如“current.naviId”表示激活的导航项。

实现菜单

和导航类似,只是需要增加两个功能:n级分组和维护。

首先参考 VuePress 设置一个json文件,保存菜单信息。

/public/docs/.nfpress/menu.json

[
{
"naviId": "1010",
"menus": [
{
"menuId": "110100",
"text": "介绍",
"description": "描述",
"icon": "FolderOpened",
"children": []
},
{
"menuId": "111100",
"text": "快速上手",
"description": "描述",
"icon": "FolderOpened",
"children": [
{
"menuId": 111120,
"text": "编辑文档项目",
"description": "",
"icon": "UserFilled",
"children": []
},
{
"menuId": 111130,
"text": "展示文档项目",
"description": "",
"icon": "UserFilled"
}
]
}
],
"ver": 1.6
},
{
"naviId": "1020",
"menus": [
{
"menuId": "21000",
"text": "导航(docNavi)",
"description": "描述",
"icon": "Star",
"children": []
}
],
"ver": 1.5
}
]
  • naviId: 关联导航项ID,可以是数字,也可以是其他字符。需要和导航项ID对应。
  • menus: 导航项对应的菜单项集合。
  • menuId: 菜单项ID,关联一个文档,可以是数字或者英文。
  • text: 菜单项名称。
  • description: 描述,考虑以后用于查询。
  • icon: 菜单使用的图标名称。
  • children: 子菜单项目,没有的话可以去掉。
  • ver: 版本号,便于更新文档。

然后用 el-menu 绑定数据渲染,因为要实现n级分组,所以做一个递归组件实现n级菜单的效果。

实现n级分组菜单

做一个递归组件实现n级分组的功能:

/lib/menu/menu-sub-edit.vue

  <template v-for="(item, index) in subMenu">
<!--树枝-->
<template v-if="item.children && item.children.length > 0">
<el-sub-menu
:key="item.menuId + '_' + index"
:index="item.menuId"
style="vertical-align: middle;"
>
<template #title>
<div style="display:inline;width: 100%;">
<component
:is="$icon[item.icon]"
style="width: 1.5em; height: 1.5em; margin-right: 8px;vertical-align: middle;"
>
</component>
<span>{{item.text}}</span>
</div>
</template>
<!--递归子菜单-->
<my-sub-menu2
:subMenu="item.children"
:dialogAddInfo="dialogAddInfo"
:dialogModInfo="dialogModInfo"
/>
</el-sub-menu>
</template>
<!--树叶-->
<el-menu-item v-else
:index="item.menuId"
:key="item.menuId + 'son_' + index"
>
<template #title>
<div style="display:inline;width: 100%;">
<span style="float: left;">
<component
:is="$icon[item.icon]"
style="width: 1.5em; height: 1.5em; margin-right: 8px;vertical-align: middle;"
>
</component>
<span >{{item.text}}</span>
</span>
</div>
</template>
</el-menu-item>
</template>
  import { ElMenuItem, ElSubMenu } from 'element-plus'
// 展示子菜单 - 递归
import mySubMenu2 from './menu-sub.vue' const props = defineProps({
subMenu: Array, // 要显示的菜单,可以n级
dialogAddInfo: Object, // 添加菜单
dialogModInfo: Object // 修改菜单
})
  • subMenu 要显示的子菜单项
  • dialogAddInfo 添加菜单的信息
  • dialogModInfo 修改菜单的信息

实现菜单的维护功能

这个就比较简单了,做个表单实现菜单的增删改即可,篇幅有限跳过。

实现 Markdown 的编辑

使用 v-md-editor 实现 Markdown 的编辑和展示,首先该插件非常好用,其次支持VuePress的主题。

建立 /lib/md/md-edit.vue 实现编辑 Markdown 的功能:

  <v-md-editor
:toolbar="toolbar"
left-toolbar="undo redo clear | tip emoji code | h bold italic strikethrough quote | ul ol table hr | link image | save | customToolbar"
:include-level="[1, 2, 3, 4]"
v-model="current.docInfo.md"
:height="editHeight + 'px'"
@save="mySave"
>
</v-md-editor>
  import { watch,ref  } from 'vue'
import { ElMessage, ElRadioGroup, ElRadioButton } from 'element-plus'
import mdController from '../service/md.js' // 状态
import { state } from '@naturefw/nf-state' // 获取当前激活的信息
const current = state.current
// 文档的加载和保存
const { loadDocById, saveDoc } = mdController() // 可见的高度
const editHeight = document.documentElement.clientHeight - 200 // 单击 保存 按钮,实现保存功能
const mySave = (text, html) => {
saveDoc(current)
}
// 定时保存
let timeout = null
let isSaved = true
const timeSave = () => {
if (isSaved) {
// 保存过了,重新计时
isSaved = false
} else {
return // 有计时,退出
} timeout = setTimeout(() => {
// 保存文档
saveDoc(current).then(() => {
ElMessage({
message: '自动保存文档成功!',
type: 'success',
})
})
isSaved = true
}, 10000)
} // 定时保存文档
watch(() => current.docInfo.md, () => {
timeSave()
}) // 根据激活的菜单项,加载对应的文档
watch( () => current.menuId, async (id) => {
const ver = current.ver
loadDocById(id, ver).then((res) => {
// 找到了文档
Object.assign(current.docInfo, res)
}).catch((res) => {
// 没有文档
Object.assign(current.docInfo, res)
})
})
  • mdController 实现文档的增删改查的controller
  • timeSave 定时保存文档,避免忘记点保存按钮

是不是挺简单的。

实现在线编写代码并且运行的功能

因为是基于Vue3建立的项目,而且也是为了写vue3相关的帮助文档,那么就有一个很实用的要求:在线写代码并且可以运行。

个人感觉这个功能还是很实用的,我知道有第三方网站提供了这种功能,但是网速有点慢,另外有一种大炮打蚊子的感觉,我只需要实现简单的代码演示。

于是我基于 vue 的 defineAsyncComponent 写了一个简单版的在线编写代码且运行的功能:

/lib/runCode/run.vue

  <div style="padding: 5px; border: 1px solid #ccc!important;">
<async-comp></async-comp>
</div>

import {
defineAsyncComponent,
ref, reactive,...
// 其他常用的vue内置指令
} from 'vue' // 使用 eval编译js代码
const mysetup = `
(function setup () {
{{code}}
})
` // 通过属性传入需要运行的代码和模板
const props = defineProps({
code: {
type: Object,
default: () => {
return {
js: '',
template: '',
style: ''
}
}
}
}) const code = props.code // 使用 defineAsyncComponent 让代码运行起来
const AsyncComp = defineAsyncComponent(
() => new Promise((resolve, reject) => {
resolve({
template: code.template, // 设置模板
style: [code.style], // 大概是样式设置,但是好像没啥效果
setup: (props, ctx) => {
const tmpJs = code.js // 获取js代码
let fun = null // 转换后的函数
try {
if (tmpJs)
fun = eval(mysetup.replace('{{code}}', tmpJs)) // 用 eval 把 字符串 变成 函数
} catch (error) {
console.error('转换出现异常:', error)
} const re = typeof fun === 'function' ? fun : () => {} return {
...re(props, ctx) // 运行函数,解构返回对象
}
}
})
})
)
  • defineAsyncComponent

    实用 defineAsyncComponent 加载组件,需要设置三个部分:模板、setup和style。

  • template: 字符串形式,可以直接传入

  • setup: js代码,可以用eval的方式进行动态编译。

  • style: 可以设置样式。

这样即可让在线编写的代码运行起来,当然功能有限,只能用于一些简单的代码演示。

导出

以上这些功能都是基于 indexedDB 进行的,想要发布的话,需要先导出为json文件。

因为浏览器里不能直接写文件,所以需要使用折中的方式:

  • 复制粘贴
  • 下载
  • 导出

复制粘贴

这个简单,用文本域显示json即可。

下载

使用 chrome 浏览器提供的下载功能下载文件。

  const uri = 'data:text/json;charset=utf-8,\ufeff' + encodeURIComponent(show.navi)

  //通过创建a标签实现
var link = document.createElement("a")
link.href = uri
//对下载的文件命名
link.download = fileName
document.body.appendChild(link)
link.click()
document.body.removeChild(link)

以上介绍的是内部原理,如果只是想简单使用的话,可以跳过,直接看下面的介绍。

用后端写文件

以上两种都不太方便,于是用node做了个简单的后端API,用于实现写入json文件的功能。

代码放在了 api文件夹里,可以使用 yarn api运行。当然需要在 package.json 里做一下设置。

  "scripts": {
"dev": "vite",
"build": "vite build --mode project",
"lib": "vite build --mode lib",
"serve": "vite preview",
"api": "node api/server.js"
},

实现一个帮助文档的项目

上面介绍的是库项目的基本原理,我们要做帮助文档的时候,并不需要那么复杂。

使用 vite2 建立一个vue3的项目,然后安装 @naturefw/press-edit,使用提供的组件即可方便的实现。

main.js

首先需要在 main.js 里面做一些设置。

import { createApp } from 'vue'
import App from './App.vue' // 设置 axios 的 baseUrl
const baseUrl = (document.location.host.includes('.gitee.io')) ?
'/doc-ui-core/' : '/' // 轻量级状态
// 设置 indexedDB 数据库,存放文档的各种信息。
import { setupIndexedDB, setupStore } from '@naturefw/press-edit'
// 初始化 indexedDB 数据库
setupIndexedDB(baseUrl) // UI库
import ElementPlus from 'element-plus'
// import 'element-plus/lib/theme-chalk/index.css'
// import 'dayjs/locale/zh-cn'
import zhCn from 'element-plus/es/locale/lang/zh-cn' // 二次封装
import { nfElementPlus } from '@naturefw/ui-elp'
// 设置icon
import installIcon from './icon/index.js' // 设置 Markdown 的配置函数
import setMarkDown from './main-md.js' // 主题
import vuepressTheme from '@kangc/v-md-editor/lib/theme/vuepress.js' const {
VueMarkdownEditor, // Markdown 的编辑器
VMdPreview // Markdown 的浏览器
} = setMarkDown(vuepressTheme) const app = createApp(App)
app.config.globalProperties.$ELEMENT = {
locale: zhCn,
size: 'small'
} app.use(setupStore) // 状态管理
.use(nfElementPlus) // 二次封装的组件
.use(installIcon) // 注册全局图标
.use(ElementPlus, { locale: zhCn, size: 'small' }) // UI库
.use(VueMarkdownEditor) // markDown编辑器
.use(VMdPreview) // markDown 显示
.mount('#app')
  • baseUrl: 根据发布平台的情况进行设置,比如这里需要设置为:“/doc-ui-core/”

  • setupIndexedDB: 初始化 indexedDB 数据库

  • setupStore: 设置状态

  • element-plus:element-plus 可以不挂载,但是css需要 import 进来,这里采用CDN的方式引入。

  • nfElementPlus: 二次封装的组件,便于实现增删改查。

  • setMarkDown: 加载 v-md-editor ,以及需要的插件。

  • vuepressTheme: 设置主题。

设置 Markdown

因为 v-md-editor 相关设置比较多,所以设置了一个单独文件进行管理:

/src/main-md.js


// Markdown 编辑器
import VueMarkdownEditor from '@kangc/v-md-editor'
import '@kangc/v-md-editor/lib/style/base-editor.css'
// 在这里引入,不被识别?
// import vuepressTheme from '@kangc/v-md-editor/lib/theme/vuepress.js'
import '@kangc/v-md-editor/lib/theme/style/vuepress.css' // 代码高亮
import Prism from 'prismjs' // emoji
import createEmojiPlugin from '@kangc/v-md-editor/lib/plugins/emoji/index'
import '@kangc/v-md-editor/lib/plugins/emoji/emoji.css' // 流程图
// import createMermaidPlugin from '@kangc/v-md-editor/lib/plugins/mermaid/cdn'
// import '@kangc/v-md-editor/lib/plugins/mermaid/mermaid.css' // todoList
import createTodoListPlugin from '@kangc/v-md-editor/lib/plugins/todo-list/index'
import '@kangc/v-md-editor/lib/plugins/todo-list/todo-list.css' // 代码行号
import createLineNumbertPlugin from '@kangc/v-md-editor/lib/plugins/line-number/index'; // 高亮代码行
import createHighlightLinesPlugin from '@kangc/v-md-editor/lib/plugins/highlight-lines/index'
import '@kangc/v-md-editor/lib/plugins/highlight-lines/highlight-lines.css' // 复制代码
import createCopyCodePlugin from '@kangc/v-md-editor/lib/plugins/copy-code/index'
import '@kangc/v-md-editor/lib/plugins/copy-code/copy-code.css' // markdown 显示器
import VMdPreview from '@kangc/v-md-editor/lib/preview'
// import '@kangc/v-md-editor/lib/style/preview.css' /**
* 设置 Markdown 编辑器 和浏览器
* @param {*} vuepressTheme
* @returns
*/
export default function setMarkDown (vuepressTheme) { // 设置 vuePress 主题
VueMarkdownEditor.use(vuepressTheme,
{
Prism,
extend(md) {
// md为 markdown-it 实例,可以在此处进行修改配置,并使用 plugin 进行语法扩展
// md.set(option).use(plugin);
},
}
) // 预览
VMdPreview.use(vuepressTheme,
{
Prism,
extend(md) {
// md为 markdown-it 实例,可以在此处进行修改配置,并使用 plugin 进行语法扩展
// md.set(option).use(plugin);
},
}
) // emoji
VueMarkdownEditor.use(createEmojiPlugin())
// 流程图
// VueMarkdownEditor.use(createMermaidPlugin())
// todoList
VueMarkdownEditor.use(createTodoListPlugin())
// 代码行号
VueMarkdownEditor.use(createLineNumbertPlugin())
// 高亮代码行
VueMarkdownEditor.use(createHighlightLinesPlugin())
// 复制代码
VueMarkdownEditor.use(createCopyCodePlugin()) // 预览的插件
VMdPreview.use(createEmojiPlugin())
VMdPreview.use(createTodoListPlugin())
VMdPreview.use(createLineNumbertPlugin())
VMdPreview.use(createHighlightLinesPlugin())
VMdPreview.use(createCopyCodePlugin()) return {
VueMarkdownEditor,
VMdPreview
} }

不多介绍了,可以根据需要选择插件。

布局

在App.vue文件里面进行整体布局

  <el-container>
<el-header>
<!--导航-->
<div style="float: left;">
<!--写网站logo、标题等-->
<h1>nf-press</h1>
</div>
<div style="float: right;min-width: 100px;height: 60px;padding-top: 13px;">
<!--写网站logo、标题等-->
<el-switch v-model="$state.current.isView" v-bind="itemProps"></el-switch>
</div>
<div style="float: right;min-width: 600px;height: 60px;">
<!--网站导航-->
<doc-navi ></doc-navi>
</div>
</el-header>
<el-container>
<!--左侧边栏-->
<el-aside width="330px">
<!--菜单-->
<doc-menu ></doc-menu>
</el-aside>
<el-main>
<!--文档区域-->
<component
:is="docControl[$state.current.isView]"
/>
</el-main>
</el-container>
</el-container>
  import { reactive, defineAsyncComponent } from 'vue'
import { ElHeader, ElContainer ,ElAside, ElMain } from 'element-plus'
import { docMenu, docNavi, config } from '@naturefw/press-edit' // 菜单 导航
import docView from './views/doc.vue' // 显示文档 // 加载菜单子控件
const docControl = {
true: docView,
false: defineAsyncComponent(() => import('./views/main.vue')) // 修改文档
} const itemProps = reactive({
'inline-prompt': true,
'active-text': '看',
'inactive-text': '写',
'active-color': '#378FEB',
'inactive-color': '#EA9712'
})
  • $state:全局状态,$state.current.isView 设置是否是浏览状态。
  • doc-navi:导航组件
  • doc-menu:菜单组件
  • docControl:根据状态选择加载显示组件或者编辑组件的字典。

这种方式虽然有点麻烦,但是比较灵活,可以根据需要进行各种灵活设置,比如添加版权信息、备案信息、广告等内容。

导航、菜单、编辑和浏览

直接使用组件实现,比较简单不搬运了,直接看源码即可。

打包发布与版本管理

需要打包的情况分为两种:第一次打包、修改代码(非在线编辑的代码)后打包。

如果只是文档内容有变化的话,只需要直接上传json文件即可,不需要再次打包。

内置了一个简单的版本管理功能,可以通过 ver.json文件里的版本号实现更新功能。

源码

https://gitee.com/nfpress/nf-press-edit

在线演示

https://nfpress.gitee.io/nf-press-edit/

demo

https://gitee.com/nfpress/doc-ui-elp

基于 vite2 + Vue3 写一个在线帮助文档工具的更多相关文章

  1. 基于 React 开发了一个 Markdown 文档站点生成工具

    Create React Doc 是一个使用 React 的 markdown 文档站点生成工具.就像 create-react-app 一样,开发者可以使用 Create React Doc 来开发 ...

  2. Swagger解决你手写API接口文档的痛

    首先,老规矩,我们在接触新事物的时候, 要对之前学习和了解过的东西做一个总结. 01 痛     苦 不做.不行 之前,前后端分离的系统由前端和后端不同的编写,我们苦逼的后端工程师会把自己已经写完的A ...

  3. Spring Boot (十五): 优雅的使用 API 文档工具 Swagger2

    1. 引言 各位在开发的过程中肯定遇到过被接口文档折磨的经历,由于 RESTful 接口的轻量化以及低耦合性,我们在修改接口后文档更新不及时,导致接口的调用方(无论是前端还是后端)经常抱怨接口与文档不 ...

  4. C# 复制PDF页面到另一个PDF文档

    C# 复制PDF页面到另一个PDF文档 有时候我们可能有这样一个需求,那就是把PDF页面从一个PDF文档复制到另一个PDF文档中.由于PDF文档并不像word文档那样好编辑,因此复制也相对没有那么容易 ...

  5. 放弃antd table,基于React手写一个虚拟滚动的表格

    缘起 标题有点夸张,并不是完全放弃antd-table,毕竟在react的生态圈里,对国人来说,比较好用的PC端组件库,也就antd了.即便经历了2018年圣诞彩蛋事件,antd的使用者也不仅不减,反 ...

  6. C# 复制一个Word文档的部分或全部内容到另一个Word文档

    C# 复制一个Word文档的部分或全部内容到另一个Word文档 我最近喜欢折腾Office软件相关的东西,想把很多Office软件提供的功能用.NET来实现,如果后期能把它用来开发一点我自己的小应用程 ...

  7. 根据Schema写出XML文档四部曲

    Schema约束文档本身就是一个XML文档,扩展名为xsd 难点:XML文档的根元素怎么写? 如下4步曲: a.首先看Schema文档,找到根元素 <?xml version="1.0 ...

  8. Java:API文档;文档注释中的javadoc标记;官方API;自己动手给项目建一个API文档

    1.什么是API文档 在Java语言中有3种注释 //单行注释 /* 多行注释 */ /** * 文档注释 */ API(应用程序接口)文档就是用javadoc命令提取文档注释生成的,html格式,用 ...

  9. 一个非常适合IT团队的在线API文档、技术文档工具 (ShowDoc)

    在逸橙呆了不到两年,开发时后端都有开发接口API,来到数库,好多后端开发和前端沟通是还是发doc文档,很不方便,我向cto反应,自己找到这个,老乡田雷(php,隔壁村的)也用过,可能某些原因选择其他的 ...

随机推荐

  1. ApacheCN PHP 译文集 20211101 更新

    PHP 入门指南 零.序言 一.PHP 入门 二.数组和循环 三.函数和类 四.数据操作 五.构建 PHP Web 应用 六.搭建 PHP 框架 七.认证与用户管理 八.建立联系人管理系统 使用 PH ...

  2. Lesson1——NumPy NumPy 安装

    NumPy 教程目录 NumPy 安装 Python 官网上的发行版是不包含 NumPy 模块的.(pip list 测试一下) 我们可以使用以下几种方法来安装. 1 使用已有的发行版本 对于许多用户 ...

  3. 「ZJOI2014」星系调查

    「ZJOI2014」星系调查 本题核心在于快速求XPs 的线性假设相斥度. 点\((x1,y1)\)到直线\(y=kx+b\)的距离的平方为\(\displaystyle {(kx1+b-y1)^2} ...

  4. Swift逻辑分支

    一. 分支的介绍 分支即if/switch/三目运算符等判断语句 通过分支语句可以控制程序的执行流程 二. if分支语句 和OC中if语句有一定的区别 判断句可以不加() 在Swift的判断句中必须有 ...

  5. java-数据库操作(JDBC)

    前言:JDBC用到的API和常用方法 DriverMannager类 加载驱动并创建与数据库的连接,通常使用Class类的静态方法forName()来实现加载驱动,使用getConnection(St ...

  6. Lesson17——NumPy 统计函数

    NumPy 教程目录 1 NumPy 统计函数 NumPy 提供了很多统计函数,用于从数组中查找最小元素,最大元素,百分位标准差和方差等. 函数说明如下 1.1 统计 method descripti ...

  7. MySQL 快速入门(一)

    目录 MySQL快速入门 简介 存储数据的演变过程 数据库分类 概念介绍 MySQL安装 MySQL命令初始 环境变量配置 MySQL环境变量配置 修改配置文件 设置新密码 忘记密码的情况 基本sql ...

  8. [LeetCode]27.移除元素(Java)

    原题地址: remove-element 题目描述: 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度. 不要使用额外的数组空间,你必 ...

  9. MyBatis封装JDBC具体实现

    关于xml等解析的工具基本均包含在org.apache.ibatis.builder包中,有包名可知基本使用建造者模式.这个包的主要功能两个: 1.解析XML配置文件和映射文件,xml子包中: 2.解 ...

  10. 《手把手教你》系列技巧篇(六十八)-java+ selenium自动化测试 - 读写excel文件 - 下篇(详细教程)

    1.简介 今天继续操作Excle,小伙伴或者童鞋们是不是觉得宏哥会介绍第三种工具操作Excle,今天不介绍了,有两种就够用了,其实一种就够用了,今天主要是来介绍如何使用不同的数据类型读取Excel文件 ...