uniApp获取通话记录
uniApp获取通话记录
首先讲一个大坑
要拿到通过记录真机调试时候必须前给足权限,必须打包成自定义基座再测试!!!!!!一定要先打包!!!!
必要权限
首先勾取manifest.json里APP模块里通讯录权限
添加以下权限
<uses-feature android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
为了怕遗漏我把我所有的权限都放出来提供参考
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.READ_LOGS"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-feature android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.FLASHLIGHT"/>
<uses-feature android:name="android.hardware.camera"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
然后打包制作自定义基座
获取通话记录代码
我也是从其他地方粘的
getCalllog(){
var CallLog = plus.android.importClass('android.provider.CallLog');
var Activity = plus.android.runtimeMainActivity();
var ContentResolver = plus.android.importClass('android.content.ContentResolver');
var resolver = Activity.getContentResolver();
plus.android.importClass(resolver);
var String = plus.android.importClass("java.lang.String");
var cs = resolver.query(CallLog.Calls.CONTENT_URI, null, null, null, CallLog.Calls.DEFAULT_SORT_ORDER);
var talist = [];
uni.showLoading({
title: "匹配通话记录中.."
});
var count = 0; // 记录多少条 用于处理循环跳出
while (plus.android.invoke(cs, "moveToNext")) {
count++;
talist.push({
xm: plus.android.invoke(cs, "getString", plus.android.invoke(cs, "getColumnIndex", CallLog.Calls.CACHED_NAME)),
telphone: plus.android.invoke(cs, "getString", plus.android.invoke(cs, "getColumnIndex", CallLog.Calls.NUMBER)),
duration: plus.android.invoke(cs, "getString", plus.android.invoke(cs, "getColumnIndex", CallLog.Calls.DURATION)),
date: plus.android.invoke(cs, "getString", plus.android.invoke(cs, "getColumnIndex", CallLog.Calls.DATE)),
type: plus.android.invoke(cs, "getString", plus.android.invoke(cs, "getColumnIndex", CallLog.Calls.TYPE))
});
if(count > 50){
break;
}
}
uni.hideLoading();
console.info("talist",talist);
},
uniApp获取通话记录
首先讲一个大坑
要拿到通过记录真机调试时候必须前给足权限,必须打包成自定义基座再测试!!!!!!一定要先打包!!!!
必要权限
首先勾取manifest.json里APP模块里通讯录权限
添加以下权限
<uses-feature android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
为了怕遗漏我把我所有的权限都放出来提供参考
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.READ_LOGS"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-feature android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.FLASHLIGHT"/>
<uses-feature android:name="android.hardware.camera"/>
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
然后打包制作自定义基座
获取通话记录代码
我也是从其他地方粘的
getCalllog(){
var CallLog = plus.android.importClass('android.provider.CallLog');
var Activity = plus.android.runtimeMainActivity();
var ContentResolver = plus.android.importClass('android.content.ContentResolver');
var resolver = Activity.getContentResolver();
plus.android.importClass(resolver);
var String = plus.android.importClass("java.lang.String");
var cs = resolver.query(CallLog.Calls.CONTENT_URI, null, null, null, CallLog.Calls.DEFAULT_SORT_ORDER);
var talist = [];
uni.showLoading({
title: "匹配通话记录中.."
});
var count = 0; // 记录多少条 用于处理循环跳出
while (plus.android.invoke(cs, "moveToNext")) {
count++;
talist.push({
xm: plus.android.invoke(cs, "getString", plus.android.invoke(cs, "getColumnIndex", CallLog.Calls.CACHED_NAME)),
telphone: plus.android.invoke(cs, "getString", plus.android.invoke(cs, "getColumnIndex", CallLog.Calls.NUMBER)),
duration: plus.android.invoke(cs, "getString", plus.android.invoke(cs, "getColumnIndex", CallLog.Calls.DURATION)),
date: plus.android.invoke(cs, "getString", plus.android.invoke(cs, "getColumnIndex", CallLog.Calls.DATE)),
type: plus.android.invoke(cs, "getString", plus.android.invoke(cs, "getColumnIndex", CallLog.Calls.TYPE))
});
if(count > 50){
break;
}
}
uni.hideLoading();
console.info("talist",talist);
},
收起阅读 »
记录一个支付宝小程序问题:切换组件出现生命周期不存在
最近写一个支付宝、微信、h5三端互通 的程序,用uniapp开发,
然后涉及到不同身份,不同的主页,所以原生的TabBar理所当然的GG,接着就自己定义了一个tabBar组件;然后发现了狗屎,,,小程序不支持component动态组件,,,就只能v-if切换组件的方式实现tabBar了;
接着,由于一开始使用的原生tabBar,所以页面是放在pages下面的,改成组件切换后,tabBar里切换的组件页面在支付宝小程序全部失去生命周期-.-||,绝了。
一开始以为是v-if的问题,后面排查完,改一个路径即可,换到components下
特此记录,狗屎小程序!!!
最近写一个支付宝、微信、h5三端互通 的程序,用uniapp开发,
然后涉及到不同身份,不同的主页,所以原生的TabBar理所当然的GG,接着就自己定义了一个tabBar组件;然后发现了狗屎,,,小程序不支持component动态组件,,,就只能v-if切换组件的方式实现tabBar了;
接着,由于一开始使用的原生tabBar,所以页面是放在pages下面的,改成组件切换后,tabBar里切换的组件页面在支付宝小程序全部失去生命周期-.-||,绝了。
一开始以为是v-if的问题,后面排查完,改一个路径即可,换到components下
特此记录,狗屎小程序!!!
收起阅读 »【分享】分享一次AppStore成功上架经验
最近刚刚在AppStore成功上架了一款VPN类软件,App采用离线打包,期间也是经历一系列问题,现在整理出来分享给有需要的朋友。
Guideline 4.3(a) - Design - Spam
这个是比较常见的打回原因,大意就是app雷同,这个雷同分2方面,一是UI/功能与其他APP雷同,二是代码雷同,根据我们上架后的修改情况来看,我们遇到的第一次4.3,是因为代码雷同(因为自始至终我们都不曾修改UI及布局)。这里说一下我们的使用过的处理方式:
- 离线打包的项目名,必须修改,不要使用默认命名“HBuilder-Hello”,项目中所有涉及到HBuilder的关键字都搜索并修改
- HBuidler发布离线资源后,使用“javascript-obfuscator”等工具进行混淆,具体方式网上很多,这里不再赘述
- 在appstoreconnect上提审/回复审核消息时,提前备注,“app使用的是uniapp这类hybrid框架,底层框架代码可能部分雷同”,
- 尽可能详细的准备app资质类文件,由于我们是VPN这类敏感软件,本身上架就有诸多限制,所以相关证书不能少,有“代码版权”最佳
- 4.3这个打回,很奇葩的,我们居然遇到2次,首次提审遇到一次,上线成功后,进行过几次修改,发布新版,后面第5次更新版时,居然再次被4.3打回,这次重点强调第3点,态度良好的跟苹果审核员沟通,就再次过了。
Guideline 5.1.1 - Legal - Data Collection and Storage
这个比较简单,根据具体反馈内容显示,苹果的内购,必须有游客购买功能,很多人初次上架都会遇到,开发相应功能即可
Guideline 2.1 - Performance - App Completeness
这个也比较简单,app不可以有假死,用户无法操作的情况出现,属于业务范畴,比较容易修改,覆盖测试到位就行
Guideline 5.1.1(v) - Data Collection and Storage
神奇的再次遇到5.1.1,而且还是成功上架后,第4次更新提审时被打回,打回原因居然是app必须要有注销功能,无奈加上注销后,审核通过
总体心得:
- 与苹果审核人员沟通,态度要诚恳,各类资质提前备好,尽量让审核人员审核方便,提审功能尽量写清楚怎么操作,入口在哪里(审核员也是人,你让他舒服,他也让你舒服,能省不少麻烦)
- 离线打包资源如果混淆不够,可以尝试对app进行加固混淆:ipaguard。不过很遗憾,我们的app有vpn进程服务,加固后找不到进程入口,所以未使用。
- 很多人遇到的隐私类问题,我们这次完美规避。因为之前上架android各大商店,频繁被隐私类问题打回(动辄是XXsdk违规收集用户隐私),这次的推送、广告、一键登录、内购等等uni-sdk一概未用,仅使用uniapp的基础sdk包,使用uniapp做UI及上层业务逻辑,有需要的sdk,尽量使用原生开发,便于找问题,比如内购、一键登录,都是自己接的原生。
- 关于热更,uniapp本身是有热更功能的,我们在android上保留了热更功能,但是为了在苹果上少一些麻烦,所以关掉了热更。
- 总体来说,使用uniapp负责上层业务,做到了一套代码,android及ios双端复用(底层tun2sock加速分别采用java及swift原生开发),省去不少重复内容的开发时间。离线打包+部分原生开发,提供了很高的自由度,在审核时,省去许多麻烦。
- 本项目是外包性质,先上架的另一个android同类app,后上架ios,均使用uniapp,开发效率不错。
欢迎加Q交流:272669509
最近刚刚在AppStore成功上架了一款VPN类软件,App采用离线打包,期间也是经历一系列问题,现在整理出来分享给有需要的朋友。
Guideline 4.3(a) - Design - Spam
这个是比较常见的打回原因,大意就是app雷同,这个雷同分2方面,一是UI/功能与其他APP雷同,二是代码雷同,根据我们上架后的修改情况来看,我们遇到的第一次4.3,是因为代码雷同(因为自始至终我们都不曾修改UI及布局)。这里说一下我们的使用过的处理方式:
- 离线打包的项目名,必须修改,不要使用默认命名“HBuilder-Hello”,项目中所有涉及到HBuilder的关键字都搜索并修改
- HBuidler发布离线资源后,使用“javascript-obfuscator”等工具进行混淆,具体方式网上很多,这里不再赘述
- 在appstoreconnect上提审/回复审核消息时,提前备注,“app使用的是uniapp这类hybrid框架,底层框架代码可能部分雷同”,
- 尽可能详细的准备app资质类文件,由于我们是VPN这类敏感软件,本身上架就有诸多限制,所以相关证书不能少,有“代码版权”最佳
- 4.3这个打回,很奇葩的,我们居然遇到2次,首次提审遇到一次,上线成功后,进行过几次修改,发布新版,后面第5次更新版时,居然再次被4.3打回,这次重点强调第3点,态度良好的跟苹果审核员沟通,就再次过了。
Guideline 5.1.1 - Legal - Data Collection and Storage
这个比较简单,根据具体反馈内容显示,苹果的内购,必须有游客购买功能,很多人初次上架都会遇到,开发相应功能即可
Guideline 2.1 - Performance - App Completeness
这个也比较简单,app不可以有假死,用户无法操作的情况出现,属于业务范畴,比较容易修改,覆盖测试到位就行
Guideline 5.1.1(v) - Data Collection and Storage
神奇的再次遇到5.1.1,而且还是成功上架后,第4次更新提审时被打回,打回原因居然是app必须要有注销功能,无奈加上注销后,审核通过
总体心得:
- 与苹果审核人员沟通,态度要诚恳,各类资质提前备好,尽量让审核人员审核方便,提审功能尽量写清楚怎么操作,入口在哪里(审核员也是人,你让他舒服,他也让你舒服,能省不少麻烦)
- 离线打包资源如果混淆不够,可以尝试对app进行加固混淆:ipaguard。不过很遗憾,我们的app有vpn进程服务,加固后找不到进程入口,所以未使用。
- 很多人遇到的隐私类问题,我们这次完美规避。因为之前上架android各大商店,频繁被隐私类问题打回(动辄是XXsdk违规收集用户隐私),这次的推送、广告、一键登录、内购等等uni-sdk一概未用,仅使用uniapp的基础sdk包,使用uniapp做UI及上层业务逻辑,有需要的sdk,尽量使用原生开发,便于找问题,比如内购、一键登录,都是自己接的原生。
- 关于热更,uniapp本身是有热更功能的,我们在android上保留了热更功能,但是为了在苹果上少一些麻烦,所以关掉了热更。
- 总体来说,使用uniapp负责上层业务,做到了一套代码,android及ios双端复用(底层tun2sock加速分别采用java及swift原生开发),省去不少重复内容的开发时间。离线打包+部分原生开发,提供了很高的自由度,在审核时,省去许多麻烦。
- 本项目是外包性质,先上架的另一个android同类app,后上架ios,均使用uniapp,开发效率不错。
欢迎加Q交流:272669509
收起阅读 »vue3+electron31+element-plus后台系统管理应用程序
整合vite5.x+electron31+pinia2+vue-i18n+echarts全新后台管理方案Vue3ElectronAdmin。提供了4种通用布局模板,支持中英文/繁体国际化解决方案、动态路由权限,实现了表格、表单、列表、图表、编辑器、错误处理等模块。
原创Electron31+Vue3+ElementPlus桌面端后台管理系统
技术栈
- 编辑器:vscode
- 框架技术:vite^5.3.4+vue^3.4.31+vue-router^4.4.0
- 跨端框架:electron^31.3.0
- 组件库:element-plus^2.7.8
- 状态管理:pinia^2.2.0
- 国际化方案:vue-i18n@9
- 图表组件:echarts^5.5.1
- markdown编辑器:md-editor-v3^4.18.0
- 模拟数据:mockjs^1.1.0
- 打包工具:electron-builder^24.13.3
- electron+vite桥接插件:vite-plugin-electron^0.28.7
功能性
1、最新前端技术栈Vite5.x、Vue3、Electron31、ElementPlus、Vue-I18n、Echarts
2、支持中英文/繁体国际化解决方案
3、支持动态权限路由、多页签缓存路由
4、封装多窗口管理器
5、内置4种通用布局模板、自由切换风格
6、整合通用的表格、表单、列表、图表、编辑器、错误处理等模块
7、高颜值UI界面、轻量级模块化、高定制性
项目结构
整个项目整合vite.js+electronjs
跨平台技术,采用vue3 setup
语法编码。
electronjs主线程配置
/**
* electron主线程配置
* @author andy
*/
import { app, BrowserWindow } from 'electron'
import { WindowManager } from '../src/windows/index.js'
// 忽略安全警告提示 Electron Security Warning (Insecure Content-Security-Policy)
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = true
const createWindow = () => {
let win = new WindowManager()
win.create({isMajor: true})
// 系统托盘管理
win.trayManager()
// 监听ipcMain事件
win.ipcManager()
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if(BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', () => {
if(process.platform !== 'darwin') app.quit()
})
electron31-vue3-admin布局模板
/**
* 通用布局模板
* @author Andy
*/
<script setup>
import { appState } from '@/pinia/modules/app'
// 引入布局模板
import Classic from './template/classic/index.vue'
import Columns from './template/columns/index.vue'
import Vertical from './template/vertical/index.vue'
import Horizontal from './template/horizontal/index.vue'
const appstate = appState()
const LayoutMap = {
'classic': Classic,
'columns': Columns,
'vertical': Vertical,
'horizontal': Horizontal
}
</script>
<template>
<div class="vuadmin__container" :style="{'--themeSkin': appstate.config.skin}">
<component :is="LayoutMap[appstate.config.layout]" />
</div>
</template>
electron31-admin国际化配置
/**
* 国际化配置
* @author YXY
*/
import { createI18n } from 'vue-i18n'
import { appState } from '@/pinia/modules/app'
// 引入语言配置
import enUS from './en-US'
import zhCN from './zh-CN'
import zhTW from './zh-TW'
// 默认语言
export const langVal = 'zh-CN'
export default async (app) => {
const appstate = appState()
const lang = appstate.lang || langVal
appstate.setLang(lang)
const i18n = createI18n({
legacy: false,
locale: lang,
messages: {
'en': enUS,
'zh-CN': zhCN,
'zh-TW': zhTW
}
})
app.use(i18n)
}
vue3封装echarts图表hook
/**
* 动态图表Hook
*/
import { onMounted, onBeforeUnmount, ref } from 'vue'
import * as echarts from 'echarts'
import elementResizeDetectorMaker from 'element-resize-detector'
export function useEcharts(el, options) {
let chartEl
let chartRef = ref(null)
let erd = elementResizeDetectorMaker()
const resizeHandle = () => {
chartEl && chartEl.resize()
}
onMounted(() => {
if(el?.value) {
chartEl = echarts.init(el.value)
chartEl.setOption(options)
chartRef.value = chartEl
}
erd.listenTo(el.value, resizeHandle)
})
onBeforeUnmount(() => {
chartEl.dispose()
erd.removeListener(el.value, resizeHandle)
})
return chartRef
}
OK,以上就是Electron31+Vue3+ElementPlus跨平台实战开发后台管理系统的一些分享。整个项目涉及到的知识点还是蛮多的,限于篇幅就暂时分享到这里。希望对大家有所帮助哈~
作者:xiaoyan2017
链接: https://segmentfault.com/a/1190000045186093
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
整合vite5.x+electron31+pinia2+vue-i18n+echarts全新后台管理方案Vue3ElectronAdmin。提供了4种通用布局模板,支持中英文/繁体国际化解决方案、动态路由权限,实现了表格、表单、列表、图表、编辑器、错误处理等模块。
原创Electron31+Vue3+ElementPlus桌面端后台管理系统
技术栈
- 编辑器:vscode
- 框架技术:vite^5.3.4+vue^3.4.31+vue-router^4.4.0
- 跨端框架:electron^31.3.0
- 组件库:element-plus^2.7.8
- 状态管理:pinia^2.2.0
- 国际化方案:vue-i18n@9
- 图表组件:echarts^5.5.1
- markdown编辑器:md-editor-v3^4.18.0
- 模拟数据:mockjs^1.1.0
- 打包工具:electron-builder^24.13.3
- electron+vite桥接插件:vite-plugin-electron^0.28.7
功能性
1、最新前端技术栈Vite5.x、Vue3、Electron31、ElementPlus、Vue-I18n、Echarts
2、支持中英文/繁体国际化解决方案
3、支持动态权限路由、多页签缓存路由
4、封装多窗口管理器
5、内置4种通用布局模板、自由切换风格
6、整合通用的表格、表单、列表、图表、编辑器、错误处理等模块
7、高颜值UI界面、轻量级模块化、高定制性
项目结构
整个项目整合vite.js+electronjs
跨平台技术,采用vue3 setup
语法编码。
electronjs主线程配置
/**
* electron主线程配置
* @author andy
*/
import { app, BrowserWindow } from 'electron'
import { WindowManager } from '../src/windows/index.js'
// 忽略安全警告提示 Electron Security Warning (Insecure Content-Security-Policy)
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = true
const createWindow = () => {
let win = new WindowManager()
win.create({isMajor: true})
// 系统托盘管理
win.trayManager()
// 监听ipcMain事件
win.ipcManager()
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if(BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', () => {
if(process.platform !== 'darwin') app.quit()
})
electron31-vue3-admin布局模板
/**
* 通用布局模板
* @author Andy
*/
<script setup>
import { appState } from '@/pinia/modules/app'
// 引入布局模板
import Classic from './template/classic/index.vue'
import Columns from './template/columns/index.vue'
import Vertical from './template/vertical/index.vue'
import Horizontal from './template/horizontal/index.vue'
const appstate = appState()
const LayoutMap = {
'classic': Classic,
'columns': Columns,
'vertical': Vertical,
'horizontal': Horizontal
}
</script>
<template>
<div class="vuadmin__container" :style="{'--themeSkin': appstate.config.skin}">
<component :is="LayoutMap[appstate.config.layout]" />
</div>
</template>
electron31-admin国际化配置
/**
* 国际化配置
* @author YXY
*/
import { createI18n } from 'vue-i18n'
import { appState } from '@/pinia/modules/app'
// 引入语言配置
import enUS from './en-US'
import zhCN from './zh-CN'
import zhTW from './zh-TW'
// 默认语言
export const langVal = 'zh-CN'
export default async (app) => {
const appstate = appState()
const lang = appstate.lang || langVal
appstate.setLang(lang)
const i18n = createI18n({
legacy: false,
locale: lang,
messages: {
'en': enUS,
'zh-CN': zhCN,
'zh-TW': zhTW
}
})
app.use(i18n)
}
vue3封装echarts图表hook
/**
* 动态图表Hook
*/
import { onMounted, onBeforeUnmount, ref } from 'vue'
import * as echarts from 'echarts'
import elementResizeDetectorMaker from 'element-resize-detector'
export function useEcharts(el, options) {
let chartEl
let chartRef = ref(null)
let erd = elementResizeDetectorMaker()
const resizeHandle = () => {
chartEl && chartEl.resize()
}
onMounted(() => {
if(el?.value) {
chartEl = echarts.init(el.value)
chartEl.setOption(options)
chartRef.value = chartEl
}
erd.listenTo(el.value, resizeHandle)
})
onBeforeUnmount(() => {
chartEl.dispose()
erd.removeListener(el.value, resizeHandle)
})
return chartRef
}
OK,以上就是Electron31+Vue3+ElementPlus跨平台实战开发后台管理系统的一些分享。整个项目涉及到的知识点还是蛮多的,限于篇幅就暂时分享到这里。希望对大家有所帮助哈~
作者:xiaoyan2017
链接: https://segmentfault.com/a/1190000045186093
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
uniapp开发的网页SEO优化方案-适用于uni-app开发的web站点, uniapp手机端网页适配优化
基于nginx服务器优化的方案, 适用于 uniapp开发的网站, 可适用于老项目
由于官网的插件暂时不支持老的项目,所以使用这种方法
本教程亲测可用, 以及上线的项目网址: http://al.jn1tea.com/
打开调试工具, 手机模式, ctrl + u 可以查看每个页面的 seo内容**
教程内容有点长, 请耐心看完
1、uniapp设置为history模式 2、nginx设置好转发规则 3、后端服务器(类同云函数),动态给模版html设置标题、描述、关键词(根据自己需要)返回html(注意:同uniapp h5 的首页html模版一致)
教程, 前置要求, 通过服务器转发,
必须能安装nginx, 以及 node.js, express 服务器框架
在宝塔, 配置反向代理配置文件, 如果是linux 注意格式问题
处理动态生成的HTML模板, 通配符匹配, uniapp前端路径都是pages/
8332, 为你的 node.js 中express 服务器框架的端口号
注意: 由于原来的系统要求, 配置了一个全局代理, 所以这个路由匹配转发需要在全局代理上面才能生效
location ~ ^/pages/.*{
proxy_pass http://127.0.0.1:8332;
proxy_http_version 1.1;
proxy_read_timeout 360s;
proxy_redirect off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
add_header X-Cache $upstream_cache_status;
}
# 以下是原来的反向代理文件, 不用动
location / {
proxy_pass http://127.0.0.1:8325;
proxy_http_version 1.1;
proxy_read_timeout 360s;
proxy_redirect off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
add_header X-Cache $upstream_cache_status;
#Set Nginx Cache
set $static_filetKzRZE5L 0;
if ( $uri ~* "\.(gif|png|jpg|css|js|woff|woff2)$" )
{
set $static_filetKzRZE5L 1;
expires 1m;
}
if ( $static_filetKzRZE5L = 0 )
{
add_header Cache-Control no-cache;
}
}
#PROXY-END/
在宝塔中安装node.js, 以及express服务器
其他linux系统可以用命令行安装,
参考教程 https://www.cnblogs.com/front-web/p/15672575.html
安装node.js, 记得设置命令行版本一致
安装完成后需要启动一个node.js的网站
首先在服务器目录下创建一个文件夹, 刚开始是空的
进入命令行终端 cd /www/wwwroot/你创建的文件夹命
在终端中运行以下命令来初始化Node.js项目:npm init -y
在终端中运行以下命令来安装Express: npm install express
安装成功后创建 views 文件夹, app.js 文件 , 修改package.json文件
package.json 启动脚本文件内容
{
"name": "putao_seo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"ejs": "^3.1.8",
"express": "^4.18.2"
}
}
app.js 文件内容, 重点, 里面内容需要根据自己的网站配置
1. 端口号, 要和上面配置反向代理一致
app.listen(8332, () => {
console.log('Server is running on port 8332');
console.log('express服务器启动成功! 端口号:8332');
});
2. 公共配置
const commonConfig = {
BASE_URL: 'http://al.jn1tea.com/', // 设置BASE_URL, 你的域名, 例如: http://al.jn1tea.com/pages/goods_details 设置为http://al.jn1tea.com/
VUE_APP_INDEX_CSS_HASH: 'asxga454' // uniapp 打包后会在static中生成一个css文件, index.xxx.css, 在这里填写
};
// 这里就是你的uniapp打包后的h5 每个页面的访问路径, seo优化就在这里修改title, description, keywords
// 想优化哪个页面就继续添加
app.get('/pages/goods_cate/goods_cate', (req, res) => {
const pageData = {
title: '商品分类页',
description: '商品分类页描述',
keywords: '商品, 分类',
...commonConfig
};
res.render('index', pageData);
});
// 下面是全部的源码, 根据个人网站自行修改
const express = require('express');
const ejs = require('ejs');
const path = require('path');
const app = express();
// 设置模板引擎
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// 静态文件目录
app.use(express.static(path.join(__dirname, 'public')));
// 公共配置
const commonConfig = {
BASE_URL: 'http://xxx.xxxcom/', // 根据实际情况设置BASE_URL
VUE_APP_INDEX_CSS_HASH: 'xxx' // 根据实际情况设置VUE_APP_INDEX_CSS_HASH
};
// 动态生成HTML
app.get('/pages/goods_cate/goods_cate', (req, res) => {
const pageData = {
title: '商品分类页',
description: '商品分类页描述',
keywords: '商品, 分类',
...commonConfig
};
res.render('index', pageData);
});
// 添加新的路由处理 /pages/store/home/index
app.get('/pages/store/home/index', (req, res) => {
const pageData = {
title: '店铺首页',
description: '店铺首页描述',
keywords: '店铺, 首页',
...commonConfig
};
res.render('index', pageData);
});
app.listen(8332, () => {
console.log('Server is running on port 8332');
console.log('express服务器启动成功! 端口号:8332');
});
进入views文件夹, 创建index.ejs 文件
// 配置文件, 刚才在app.js 的文件会动态解析到这里的title等标签中
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title><%= title %> | 葡萄有约</title>
<meta name="Keywords" content="<%= keywords %>" />
<meta name="Description" content="<%= description %>" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')
if(window.location.protocol == 'http:'){
document.write('<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">')
}
</script>
<link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" />
</head>
<body>
<noscript>
<strong>Please enable JavaScript to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
接下来创建一个node.js 网站
启动网站,
cd进入刚才初始化创建的目录, 用终端打开
输入命令 node app.js 启动express 服务器, 看到日志说明启动成功
注意, 如果中途修改配置文件, 记得重启 node app.js, 同理nginx 修改也要重启生效
如果没问题, 就可以访问你配置后的页面, ctrl + u 查看是否生效
基于nginx服务器优化的方案, 适用于 uniapp开发的网站, 可适用于老项目
由于官网的插件暂时不支持老的项目,所以使用这种方法
本教程亲测可用, 以及上线的项目网址: http://al.jn1tea.com/
打开调试工具, 手机模式, ctrl + u 可以查看每个页面的 seo内容**
教程内容有点长, 请耐心看完
1、uniapp设置为history模式 2、nginx设置好转发规则 3、后端服务器(类同云函数),动态给模版html设置标题、描述、关键词(根据自己需要)返回html(注意:同uniapp h5 的首页html模版一致)
教程, 前置要求, 通过服务器转发,
必须能安装nginx, 以及 node.js, express 服务器框架
在宝塔, 配置反向代理配置文件, 如果是linux 注意格式问题
处理动态生成的HTML模板, 通配符匹配, uniapp前端路径都是pages/
8332, 为你的 node.js 中express 服务器框架的端口号
注意: 由于原来的系统要求, 配置了一个全局代理, 所以这个路由匹配转发需要在全局代理上面才能生效
location ~ ^/pages/.*{
proxy_pass http://127.0.0.1:8332;
proxy_http_version 1.1;
proxy_read_timeout 360s;
proxy_redirect off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
add_header X-Cache $upstream_cache_status;
}
# 以下是原来的反向代理文件, 不用动
location / {
proxy_pass http://127.0.0.1:8325;
proxy_http_version 1.1;
proxy_read_timeout 360s;
proxy_redirect off;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header REMOTE-HOST $remote_addr;
add_header X-Cache $upstream_cache_status;
#Set Nginx Cache
set $static_filetKzRZE5L 0;
if ( $uri ~* "\.(gif|png|jpg|css|js|woff|woff2)$" )
{
set $static_filetKzRZE5L 1;
expires 1m;
}
if ( $static_filetKzRZE5L = 0 )
{
add_header Cache-Control no-cache;
}
}
#PROXY-END/
在宝塔中安装node.js, 以及express服务器
其他linux系统可以用命令行安装,
参考教程 https://www.cnblogs.com/front-web/p/15672575.html
安装node.js, 记得设置命令行版本一致
安装完成后需要启动一个node.js的网站
首先在服务器目录下创建一个文件夹, 刚开始是空的
进入命令行终端 cd /www/wwwroot/你创建的文件夹命
在终端中运行以下命令来初始化Node.js项目:npm init -y
在终端中运行以下命令来安装Express: npm install express
安装成功后创建 views 文件夹, app.js 文件 , 修改package.json文件
package.json 启动脚本文件内容
{
"name": "putao_seo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node app.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"ejs": "^3.1.8",
"express": "^4.18.2"
}
}
app.js 文件内容, 重点, 里面内容需要根据自己的网站配置
1. 端口号, 要和上面配置反向代理一致
app.listen(8332, () => {
console.log('Server is running on port 8332');
console.log('express服务器启动成功! 端口号:8332');
});
2. 公共配置
const commonConfig = {
BASE_URL: 'http://al.jn1tea.com/', // 设置BASE_URL, 你的域名, 例如: http://al.jn1tea.com/pages/goods_details 设置为http://al.jn1tea.com/
VUE_APP_INDEX_CSS_HASH: 'asxga454' // uniapp 打包后会在static中生成一个css文件, index.xxx.css, 在这里填写
};
// 这里就是你的uniapp打包后的h5 每个页面的访问路径, seo优化就在这里修改title, description, keywords
// 想优化哪个页面就继续添加
app.get('/pages/goods_cate/goods_cate', (req, res) => {
const pageData = {
title: '商品分类页',
description: '商品分类页描述',
keywords: '商品, 分类',
...commonConfig
};
res.render('index', pageData);
});
// 下面是全部的源码, 根据个人网站自行修改
const express = require('express');
const ejs = require('ejs');
const path = require('path');
const app = express();
// 设置模板引擎
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// 静态文件目录
app.use(express.static(path.join(__dirname, 'public')));
// 公共配置
const commonConfig = {
BASE_URL: 'http://xxx.xxxcom/', // 根据实际情况设置BASE_URL
VUE_APP_INDEX_CSS_HASH: 'xxx' // 根据实际情况设置VUE_APP_INDEX_CSS_HASH
};
// 动态生成HTML
app.get('/pages/goods_cate/goods_cate', (req, res) => {
const pageData = {
title: '商品分类页',
description: '商品分类页描述',
keywords: '商品, 分类',
...commonConfig
};
res.render('index', pageData);
});
// 添加新的路由处理 /pages/store/home/index
app.get('/pages/store/home/index', (req, res) => {
const pageData = {
title: '店铺首页',
description: '店铺首页描述',
keywords: '店铺, 首页',
...commonConfig
};
res.render('index', pageData);
});
app.listen(8332, () => {
console.log('Server is running on port 8332');
console.log('express服务器启动成功! 端口号:8332');
});
进入views文件夹, 创建index.ejs 文件
// 配置文件, 刚才在app.js 的文件会动态解析到这里的title等标签中
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title><%= title %> | 葡萄有约</title>
<meta name="Keywords" content="<%= keywords %>" />
<meta name="Description" content="<%= description %>" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)'))
document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />')
if(window.location.protocol == 'http:'){
document.write('<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">')
}
</script>
<link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css" />
</head>
<body>
<noscript>
<strong>Please enable JavaScript to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
接下来创建一个node.js 网站
启动网站,
cd进入刚才初始化创建的目录, 用终端打开
输入命令 node app.js 启动express 服务器, 看到日志说明启动成功
注意, 如果中途修改配置文件, 记得重启 node app.js, 同理nginx 修改也要重启生效
如果没问题, 就可以访问你配置后的页面, ctrl + u 查看是否生效
团队接单!诚心做事,敏捷团队,线上案例多
团队成员来自深圳、上海杭州等地,人均十年工作经验,现回家四线城市发展
团队成员在一起(敏捷团队)
前端全栈,主要围绕Uniapp、Vue2,3,React等
后端全栈,主要以Java、PHP、Golang三者为主
服务端,精通服务器部署,Docker部署,运维
现有第三方资源清单
1、在线支付(费率优惠)
2、服务器共享(合作后上线初期或者中小项目免费部署使用)
3、域名商业化共享(二级域名)
有以上几点可以快速满足需求落地,直接利用我方已有的资源
以定制需求制作系统为主,根据需求初步制作功能清单,评估工时进行报价,价格合理欢迎来谈,有需要的加V或电联:(尧)13539565631
团队成员来自深圳、上海杭州等地,人均十年工作经验,现回家四线城市发展
团队成员在一起(敏捷团队)
前端全栈,主要围绕Uniapp、Vue2,3,React等
后端全栈,主要以Java、PHP、Golang三者为主
服务端,精通服务器部署,Docker部署,运维
现有第三方资源清单
1、在线支付(费率优惠)
2、服务器共享(合作后上线初期或者中小项目免费部署使用)
3、域名商业化共享(二级域名)
有以上几点可以快速满足需求落地,直接利用我方已有的资源
以定制需求制作系统为主,根据需求初步制作功能清单,评估工时进行报价,价格合理欢迎来谈,有需要的加V或电联:(尧)13539565631
收起阅读 »vue3兼容APP和微信小程序的base64图片保存到相册的方法
<view style="padding:40rpx;">
<canvas id="myCanvas" canvas-id="myCanvas" type="2d" style="width: 670rpx; height: 670rpx;" @longpress="saveCode"></canvas>
</view>
API请求获取得到buffer
codeSrc.value = "data:image/png;base64," + res.data.buffer; // <image :src="codeSrc"></image>仅展示,要保存到相册,无法直接调用saveImageToPhotosAlbum,也无法间接通过getImageInfo、downloadFile、saveFile获得的临时文件地址再保存,故采用canvasToTempFilePath API解决;如您后端返回是图链该方法不适用。
const bufferRaw = res.data.buffer
由于个人原因小程序端fields获取的context接连抽风绘制不出图形
uni.createSelectorQuery().in(app.proxy).select('#myCanvas').context((res) => {let ctx=res})
uni.createSelectorQuery().in(app.proxy).select('#myCanvas').fields({node: true,context: true})((res) => {let canvas=res[0].node;let ctx=canvas.getContext('2d'); //或 let ctx=res[0].context})
所以小程序只能从canvas入手,最终
// 确保canvas已经挂载后执行下面的代码片段
const tempFilePath = ref("")
// #ifdef APP
const ctx = uni.createCanvasContext("myCanvas", app.proxy)
ctx.rect(0, 0, uni.upx2px(670), uni.upx2px(670))
ctx.setFillStyle('white')
ctx.fill()
ctx.drawImage(codeSrc.value, 0, 0, uni.upx2px(
670), uni.upx2px(670));
// !!!一定要在回调中获得这个canvas的临时地址
ctx.draw(false, async () => {
uni.canvasToTempFilePath({
canvasId: "myCanvas",
success: function(res) {
console.log(res
.tempFilePath)
tempFilePath.value = res
.tempFilePath
// 能预览就是画成功
// uni.previewImage({
// urls: [res
// .tempFilePath
// ],
// })
}
})
})
// #endif
// #ifdef MP
// 小程序废弃了createCanvasContext
const query = uni.createSelectorQuery().in(app.proxy)
query.select('#myCanvas')
.fields({
node: true,
size: true
})
.exec(async (res) => {
// console.log(res)
let canvas = res[0].node
let ctx = canvas.getContext('2d')
// console.log(ctx, canvas)
const dpr = wx.getSystemInfoSync().pixelRatio
canvas.width = res[0].width * dpr
canvas.height = res[0].height * dpr
ctx.scale(dpr, dpr)
const fsm = wx.getFileSystemManager() // 文件管理器
const fname = app.proxy.$utils.$helper.generateRandomString(16)
const FILE_BASE_NAME = `tmp_base64src_${fname}` // 文件名
const format = 'png' // 文件后缀
const buffer = wx.base64ToArrayBuffer(bufferRaw) // base 转二进制
const filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.${format}` // 文件名
fsm.writeFile({ // 写文件
filePath,
data: buffer,
encoding: 'binary',
success: (res) => {
// 能预览就是画成功
// wx.previewImage({
// urls: [filePath],
// })
var img = canvas.createImage();
img.src = filePath
img.onload = function() {
ctx.drawImage(img, 0, 0,
uni
.upx2px(
670), uni.upx2px(670));
// ctx.draw()
uni.canvasToTempFilePath({
canvasId: 'myCanvas',
canvas: canvas,
success: function(res) {
console.log(res
.tempFilePath)
tempFilePath.value = res
.tempFilePath
},
fail: function(error) {
console.error(error)
}
}, app.proxy);
}
},
fail: (err) => {
console.error(err)
}
})
})
// #endif
// 保存到相册
const saveCode = () => {
uni.saveImageToPhotosAlbum({
filePath: tempFilePath.value,
success: function() {
uni.showToast({
title: '保存成功',
icon: 'success'
});
},
fail: function(error) {
uni.showToast({
title: '未保存成功',
icon: 'none'
});
}
});
}
<view style="padding:40rpx;">
<canvas id="myCanvas" canvas-id="myCanvas" type="2d" style="width: 670rpx; height: 670rpx;" @longpress="saveCode"></canvas>
</view>
API请求获取得到buffer
codeSrc.value = "data:image/png;base64," + res.data.buffer; // <image :src="codeSrc"></image>仅展示,要保存到相册,无法直接调用saveImageToPhotosAlbum,也无法间接通过getImageInfo、downloadFile、saveFile获得的临时文件地址再保存,故采用canvasToTempFilePath API解决;如您后端返回是图链该方法不适用。
const bufferRaw = res.data.buffer
由于个人原因小程序端fields获取的context接连抽风绘制不出图形
uni.createSelectorQuery().in(app.proxy).select('#myCanvas').context((res) => {let ctx=res})
uni.createSelectorQuery().in(app.proxy).select('#myCanvas').fields({node: true,context: true})((res) => {let canvas=res[0].node;let ctx=canvas.getContext('2d'); //或 let ctx=res[0].context})
所以小程序只能从canvas入手,最终
// 确保canvas已经挂载后执行下面的代码片段
const tempFilePath = ref("")
// #ifdef APP
const ctx = uni.createCanvasContext("myCanvas", app.proxy)
ctx.rect(0, 0, uni.upx2px(670), uni.upx2px(670))
ctx.setFillStyle('white')
ctx.fill()
ctx.drawImage(codeSrc.value, 0, 0, uni.upx2px(
670), uni.upx2px(670));
// !!!一定要在回调中获得这个canvas的临时地址
ctx.draw(false, async () => {
uni.canvasToTempFilePath({
canvasId: "myCanvas",
success: function(res) {
console.log(res
.tempFilePath)
tempFilePath.value = res
.tempFilePath
// 能预览就是画成功
// uni.previewImage({
// urls: [res
// .tempFilePath
// ],
// })
}
})
})
// #endif
// #ifdef MP
// 小程序废弃了createCanvasContext
const query = uni.createSelectorQuery().in(app.proxy)
query.select('#myCanvas')
.fields({
node: true,
size: true
})
.exec(async (res) => {
// console.log(res)
let canvas = res[0].node
let ctx = canvas.getContext('2d')
// console.log(ctx, canvas)
const dpr = wx.getSystemInfoSync().pixelRatio
canvas.width = res[0].width * dpr
canvas.height = res[0].height * dpr
ctx.scale(dpr, dpr)
const fsm = wx.getFileSystemManager() // 文件管理器
const fname = app.proxy.$utils.$helper.generateRandomString(16)
const FILE_BASE_NAME = `tmp_base64src_${fname}` // 文件名
const format = 'png' // 文件后缀
const buffer = wx.base64ToArrayBuffer(bufferRaw) // base 转二进制
const filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.${format}` // 文件名
fsm.writeFile({ // 写文件
filePath,
data: buffer,
encoding: 'binary',
success: (res) => {
// 能预览就是画成功
// wx.previewImage({
// urls: [filePath],
// })
var img = canvas.createImage();
img.src = filePath
img.onload = function() {
ctx.drawImage(img, 0, 0,
uni
.upx2px(
670), uni.upx2px(670));
// ctx.draw()
uni.canvasToTempFilePath({
canvasId: 'myCanvas',
canvas: canvas,
success: function(res) {
console.log(res
.tempFilePath)
tempFilePath.value = res
.tempFilePath
},
fail: function(error) {
console.error(error)
}
}, app.proxy);
}
},
fail: (err) => {
console.error(err)
}
})
})
// #endif
// 保存到相册
const saveCode = () => {
uni.saveImageToPhotosAlbum({
filePath: tempFilePath.value,
success: function() {
uni.showToast({
title: '保存成功',
icon: 'success'
});
},
fail: function(error) {
uni.showToast({
title: '未保存成功',
icon: 'none'
});
}
});
}
收起阅读 »
分享自用HBuilderX主题 仿 VsCode Default Dark Modern主题
自用 基于HBuiderX酷黑主题上修改的 仿VsCode的 现代深色Default Dark Modern 主题
有一些缺陷,比如:
- 不会修改菜单的背景颜色,所以是酷黑主题原有的颜色
- 没有修改代码颜色,是酷黑主题原有的颜色
如下图
主题预览图:
{
"editor.colorScheme": "Monokai",
"workbench.colorCustomizations": {
"[Default]": {},
"[Monokai]": {
"console.background":"#181818",
"menubar.background":"#181818",
"editor.background": "#1f1f1f",
"editor.foreground": "#808080",
"editor.indentguide": "#404040",
"editor.indicator.sameword": "#343a40",
"editor.selectRegion": "#2a2b2d",
"editor.selection": "#264f78",
"editor.unactive_selection.background": "#9e6a03",
"editor.whitespace": "#1f1f1f",
"editorGroup.border": "#333333",
"editorGroupHeader.tabsBackground": "#181818",
"editorSuggestWidget.background": "#202020",
"editorSuggestWidget.border": "#454545",
"editorSuggestWidget.selectedBackground": "#454545",
"focusBorder": "#0078d4",
"input.background": "#313131",
"input.foreground": "#c3c3c3",
"input.searchbar.foreground": "#989898",
"input.searchbar.foreground.notfinded": "#aeaeae",
"inputList.border": "#313131",
"inputList.foreground": "#8b8b8b",
"inputList.hoverBackground": "#2a2d2e",
"inputList.titleColor": "#cccccc",
"inputValidation.infoBackground": "#222222",
"list.activeSelectionBackground": "#04395e",
"list.activeSelectionForeground": "#ffffff",
"list.foreground": "#cccccc",
"list.highlightForeground": "#ffffff",
"list.hoverBackground": "#2a2d2e",
"minimap.handle.background": "#1f1f1f",
"outlineBackground": "#1f1f1f",
"scrollbarSlider.background": "#434343",
"scrollbarSlider.hoverBackground": "#4f4f4f",
"sideBar.background": "#181818",
"sideBar.border": "#2b2b2b",
"statusBar.background": "#181818",
"statusBar.button.hoverbackground": "#343434",
"statusBar.foreground": "#cccccc",
"tab.activeBackground": "#1f1f1f",
"tab.activeForeground": "#ffffff",
"tab.border": "#2b2b2b",
"tab.hoverBackground": "#1f1f1f",
"tab.inactiveBackground": "#181818",
"tab.inactiveForeground": "#9d9d9d",
"tab.unfocusedActiveForeground": "#737373",
"tab.unfocusedHoverBackground": "#1f1f1f",
"tab.unfocusedInactiveForeground": "#181818",
"terminal.background": "#181818",
"toolBar.background": "#181818",
"toolBar.border": "#2b2b2b",
"toolBar.hoverBackground": "#2d2e2e"
}
},
"editor.tokenColorCustomizations": {
"[Default]": {},
"[Monokai]": {
"rules": [
{
"scope": [
"comment"
],
"settings": {
"foreground": "#6a9955"
}
}
]
}
}
}
自用 基于HBuiderX酷黑主题上修改的 仿VsCode的 现代深色Default Dark Modern 主题
有一些缺陷,比如:
- 不会修改菜单的背景颜色,所以是酷黑主题原有的颜色
- 没有修改代码颜色,是酷黑主题原有的颜色
如下图
主题预览图:
{
"editor.colorScheme": "Monokai",
"workbench.colorCustomizations": {
"[Default]": {},
"[Monokai]": {
"console.background":"#181818",
"menubar.background":"#181818",
"editor.background": "#1f1f1f",
"editor.foreground": "#808080",
"editor.indentguide": "#404040",
"editor.indicator.sameword": "#343a40",
"editor.selectRegion": "#2a2b2d",
"editor.selection": "#264f78",
"editor.unactive_selection.background": "#9e6a03",
"editor.whitespace": "#1f1f1f",
"editorGroup.border": "#333333",
"editorGroupHeader.tabsBackground": "#181818",
"editorSuggestWidget.background": "#202020",
"editorSuggestWidget.border": "#454545",
"editorSuggestWidget.selectedBackground": "#454545",
"focusBorder": "#0078d4",
"input.background": "#313131",
"input.foreground": "#c3c3c3",
"input.searchbar.foreground": "#989898",
"input.searchbar.foreground.notfinded": "#aeaeae",
"inputList.border": "#313131",
"inputList.foreground": "#8b8b8b",
"inputList.hoverBackground": "#2a2d2e",
"inputList.titleColor": "#cccccc",
"inputValidation.infoBackground": "#222222",
"list.activeSelectionBackground": "#04395e",
"list.activeSelectionForeground": "#ffffff",
"list.foreground": "#cccccc",
"list.highlightForeground": "#ffffff",
"list.hoverBackground": "#2a2d2e",
"minimap.handle.background": "#1f1f1f",
"outlineBackground": "#1f1f1f",
"scrollbarSlider.background": "#434343",
"scrollbarSlider.hoverBackground": "#4f4f4f",
"sideBar.background": "#181818",
"sideBar.border": "#2b2b2b",
"statusBar.background": "#181818",
"statusBar.button.hoverbackground": "#343434",
"statusBar.foreground": "#cccccc",
"tab.activeBackground": "#1f1f1f",
"tab.activeForeground": "#ffffff",
"tab.border": "#2b2b2b",
"tab.hoverBackground": "#1f1f1f",
"tab.inactiveBackground": "#181818",
"tab.inactiveForeground": "#9d9d9d",
"tab.unfocusedActiveForeground": "#737373",
"tab.unfocusedHoverBackground": "#1f1f1f",
"tab.unfocusedInactiveForeground": "#181818",
"terminal.background": "#181818",
"toolBar.background": "#181818",
"toolBar.border": "#2b2b2b",
"toolBar.hoverBackground": "#2d2e2e"
}
},
"editor.tokenColorCustomizations": {
"[Default]": {},
"[Monokai]": {
"rules": [
{
"scope": [
"comment"
],
"settings": {
"foreground": "#6a9955"
}
}
]
}
}
}
收起阅读 »
uni-app 最专业的代码生成器
mui 专业代码生成器
1.数据库专业工具
- 后端专业工具
- UI 采用MUI 一键生成
欢迎讨论,提供技术支持
下载地址:
https://download.csdn.net/download/qq512929249/89639950
mui 专业代码生成器
1.数据库专业工具
- 后端专业工具
- UI 采用MUI 一键生成
欢迎讨论,提供技术支持
下载地址:
https://download.csdn.net/download/qq512929249/89639950