基于 vite2 + Vue3 写一个在线帮助文档工具
wptr33 2024-11-14 19:22 59 浏览
提起帮助文档,想必大家都会想到 VuePress等,我也体验了一下,但是感觉和我的思路不太一样,我希望的是那种可以直接在线编辑文档,然后无需编译就可以直接发布的方式,另外可以在线写(修改)代码并且运行的效果。
VuePress 是“静态网站生成器”,需要我们自行编写文档,然后交给VuePress变成网站,VuePress 并没有提供编写环境,我知道有很多编写 Markdown 的方式,但是我还是喜欢编写、浏览合为“一体”的方式。
似乎没有,那么 —— 自己动手丰衣足食吧,开干!
技术栈
- vite: ^2.7.0
- vue: ^3.2.23
- axios: ^0.25.0 获取json格式的配置和文档(CDN方式引入)
- 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 即可。
基本功能就是这样,心急的可以先看在线演示和源码。
- 在线演示:
https://nfpress.gitee.io/nf-press-edit/
- 源码:
nf-press-edit_帮助文档的管理平台: 在线文档的编辑环境,可以编写文档。
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": "帮助文档/nf-press-edit_帮助文档的管理平台"
},
{
"naviId": "1390",
"text": "在线演示",
"link": "在线编写帮助文档"
},
{
"naviId": "1395",
"text": "我要提意见",
"link": "Issues · 帮助文档/nf-press-edit_帮助文档的管理平台 - Gitee.com"
}
]
}
- 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文件里的版本号实现更新功能。
相关推荐
- [常用工具] git基础学习笔记_git工具有哪些
-
添加推送信息,-m=messagegitcommit-m“添加注释”查看状态...
- centos7安装部署gitlab_centos7安装git服务器
-
一、Gitlab介1.1gitlab信息GitLab是利用RubyonRails一个开源的版本管理系统,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目。...
- 太高效了!玩了这么久的Linux,居然不知道这7个终端快捷键
-
作为Linux用户,大家肯定在Linux终端下敲过无数的命令。有的命令很短,比如:ls、cd、pwd之类,这种命令大家毫无压力。但是,有些命令就比较长了,比如:...
- 提高开发速度还能保证质量的10个小窍门
-
养成坏习惯真是分分钟的事儿,而养成好习惯却很难。我发现,把那些对我有用的习惯写下来,能让我坚持住已经花心思养成的好习惯。...
- 版本管理最好用的工具,你懂多少?
-
版本控制(Revisioncontrol)是一种在开发的过程中用于管理我们对文件、目录或工程等内容的修改历史,方便查看更改历史记录,备份以便恢复以前的版本的软件工程技术。...
- Git回退到某个版本_git回退到某个版本详细步骤
-
在开发过程,有时会遇到合并代码或者合并主分支代码导致自己分支代码冲突等问题,这时我们需要回退到某个commit_id版本1,查看所有历史版本,获取git的某个历史版本id...
- Kubernetes + Jenkins + Harbor 全景实战手册
-
Kubernetes+Jenkins+Harbor全景实战手册在现代企业级DevOps体系中,Kubernetes(K8s)、Jenkins和Harbor组成的CI/CD流水...
- git常用命令整理_git常见命令
-
一、Git仓库完整迁移完整迁移,就是指,不仅将所有代码移植到新的仓库,而且要保留所有的commit记录1.随便找个文件夹,从原地址克隆一份裸版本库...
- 第三章:Git分支管理(多人协作基础)
-
3.1分支基本概念分支是Git最强大的功能之一,它允许你在主线之外创建独立的开发线路,互不干扰。理解分支的工作原理是掌握Git的关键。核心概念:HEAD:指向当前分支的指针...
- 云效Codeup怎么创建分支并进行分支管理
-
云效Codeup怎么创建分支并进行分支管理,分支是为了将修改记录分叉备份保存,不受其他分支的影响,所以在同一个代码库里可以同时进行多个修改。创建仓库时,会自动创建Master分支作为默认分支,后续...
- git 如何删除本地和远程分支?_git怎么删除远程仓库
-
Git分支对于开发人员来说是一项强大的功能,但要维护干净的存储库,就需要知道如何删除过时的分支。本指南涵盖了您需要了解的有关本地和远程删除Git分支的所有信息。了解Git分支...
- git 实现一份代码push到两个git地址上
-
一直以来想把自己的博客代码托管到github和coding上想一次更改一次push两个地址一起更新今天有空查资料实践了下本博客的github地址coding的git地址如果是Gi...
- git操作:cherry-pick和rebase_git cherry-pick bad object
-
在编码中经常涉及到分支之间的代码同步问题,那就需要cherry-pick和rebase命令问题:如何将某个分支的多个commit合并到另一个分支,并在另一个分支只保留一个commit记录解答:假设有两...
- 模型文件硬塞进 Git,GitHub 直接打回原形:使用Git-LFS管理大文件
-
前言最近接手了一个计算机视觉项目代码是屎山就不说了,反正我也不看代码主要就是构建一下docker镜像,测试一下部署的兼容性这本来不难但是,国内服务器的网络环境实在是恶劣,需要配置各种镜像(dock...
- 防弹少年团田柾国《Euphoria》2周年 获世界实时趋势榜1位 恭喜呀
-
当天韩国时间凌晨3时左右,该曲在Twitter上以“2YearsWithEuphoria”的HashTag登上了世界趋势1位。在韩国推特实时趋势中,从上午开始到现在“Euphoria2岁”的Has...
- 一周热门
-
-
C# 13 和 .NET 9 全知道 :13 使用 ASP.NET Core 构建网站 (1)
-
程序员的开源月刊《HelloGitHub》第 71 期
-
详细介绍一下Redis的Watch机制,可以利用Watch机制来做什么?
-
假如有100W个用户抢一张票,除了负载均衡办法,怎么支持高并发?
-
Java面试必考问题:什么是乐观锁与悲观锁
-
如何将AI助手接入微信(打开ai手机助手)
-
SparkSQL——DataFrame的创建与使用
-
redission YYDS spring boot redission 使用
-
一文带你了解Redis与Memcached? redis与memcached的区别
-
如何利用Redis进行事务处理呢? 如何利用redis进行事务处理呢英文
-
- 最近发表
- 标签列表
-
- git pull (33)
- git fetch (35)
- mysql insert (35)
- mysql distinct (37)
- concat_ws (36)
- java continue (36)
- jenkins官网 (37)
- mysql 子查询 (37)
- python元组 (33)
- mybatis 分页 (35)
- vba split (37)
- redis watch (34)
- python list sort (37)
- nvarchar2 (34)
- mysql not null (36)
- hmset (35)
- python telnet (35)
- python readlines() 方法 (36)
- munmap (35)
- docker network create (35)
- redis 集合 (37)
- python sftp (37)
- setpriority (34)
- c语言 switch (34)
- git commit (34)