编码
echo -n hello | base64
#或者
echo -n 'hello' | base64
#返回
aGVsbG8=
解码
echo -n aGVsbG8= |base64
#或者
echo -n 'aGVsbG8=' |base64
#返回
hello
echo -n hello | base64
#或者
echo -n 'hello' | base64
#返回
aGVsbG8=
echo -n aGVsbG8= |base64
#或者
echo -n 'aGVsbG8=' |base64
#返回
hello
在微信小程序中,App.onLaunch
和 Page.onLoad
是两个生命周期方法。App.onLaunch
是当小程序启动时触发的方法,而 Page.onLoad
是当页面加载时触发的方法。因为 App.onLaunch
和 Page.onLoad
是异步执行的,有时 Page.onLoad
会在 App.onLaunch
完成之前执行。这可能导致页面在获取用户信息之前就已经加载完成。
this.userInfoReadyCallback
是一种解决方案,用于处理这种情况。它是一个回调函数,用于在全局数据(例如用户信息)准备就绪时通知页面。
原理如下:
App.onLaunch
方法中,你会尝试获取用户信息并将其存储到全局变量 globalData.userInfo
中。wx.getUserInfo
是一个网络请求,它可能在 Page.onLoad
之后才返回。因此,在 App.onLaunch
中,你可以检查是否已经定义了 this.userInfoReadyCallback
。如果已经定义了,说明页面已经加载完毕,并且需要在用户信息准备就绪时接收通知。Page.onLoad
方法中,你可以检查全局变量 globalData.userInfo
是否已经存在。如果不存在,说明用户信息还未准备就绪,此时你可以定义 this.userInfoReadyCallback
并将其设置为一个处理用户信息的函数。这样,当用户信息准备就绪时,App.onLaunch
方法会调用 this.userInfoReadyCallback
,从而通知页面并处理用户信息。这种方法确保了页面在处理用户信息时,不会因为数据未准备就绪而出现错误。
小程序默认的app.js
// app.js
App({
onLaunch: function () {
// 展示本地存储能力
var logs = wx.getStorageSync('logs') || []
logs.unshift(Date.now())
wx.setStorageSync('logs', logs)
// 登录
wx.login({
success: res => {
// 发送 res.code 到后台换取 openId, sessionKey, unionId
}
})
// 获取用户信息
wx.getSetting({
success: res => {
if (res.authSetting['scope.userInfo']) {
// 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
wx.getUserInfo({
success: res => {
// 可以将 res 发送给后台解码出 unionId
this.globalData.userInfo = res.userInfo
// 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
// 所以此处加入 callback 以防止这种情况
if (this.userInfoReadyCallback) {
this.userInfoReadyCallback(res)
}
}
})
}
}
})
},
globalData: {
userInfo: null
}
})
如果想确保在page页面能获取用户信息,需要判断`app.globalData.userInfo`是否存在,不存在的话调用app.userInfoReadyCallback
// pages/somePage/somePage.js
Page({
data: {
userInfo: null
},
onLoad: function () {
// 获取全局 App 实例
const app = getApp();
// 检查全局数据 globalData.userInfo 是否已经存在
if (app.globalData.userInfo) {
// 用户信息已经存在,可以直接在页面中使用
this.setData({
userInfo: app.globalData.userInfo
});
} else {
// 用户信息不存在,定义一个处理用户信息的函数
app.userInfoReadyCallback = (res) => {
this.setData({
userInfo: res.data.data
});
};
}
},
// 其他页面方法...
});
可以通过以下步骤来查看服务器端口是否通畅:
telnet 服务器IP地址 80
如果连接成功,则表示该端口通畅;如果连接失败,则表示该端口不通畅。
nc -zv 服务器IP地址 443
如果连接成功,则表示该端口通畅;如果连接失败,则表示该端口不通畅。
ping 服务器IP地址
如果服务器可达,则表示网络连接正常;如果服务器不可达,则表示网络连接故障。
需要注意的是,不同的操作系统可能有不同的命令行工具,以上命令仅为示例。
在开发微信小程序时,我遇到了一个问题。当用户手动输入昵称并提交时,一切正常。
然而,在这情况下会出现问题。当用户点击输入框时,微信系统会提示“用微信昵称”。若用户选择此提示,昵称输入框会自动填充当前微信昵称,然后点击保存按钮,实际上nickname输入框是没有数据的。
问题重现一下,在input输入框上我添加了监听事bindinput=”onChangeNickname”.
如下:
<form bindsubmit="save">
...
<input type="nickname" class="weui-input" name="nickname" placeholder="请输入昵称" bindinput="onChangeNickname" value="{{nickname}}"/>
...
<button form-type="submit" type="primary" style="margin-top: 100rpx;">保存</button>
</form>
js逻辑如下:
Page({
data: {
nickname:'',
},
onChangeNickname(e:any){
const nickname = e.detail.value;
this.setData({nickname})
},
save() {
const nickname = this.data.nickname;
wx.request({
...
//api逻辑
})
}
})
这个监听事件只在用户正常输入时起作用,如果想上面说的那样选择系统的“用微信昵称”,其实这个nickname是没变化的。
(这段也没解决问题,如果想解决问题直接第三段)
从小程序的文档获得input的一个属性bindnicknamereview,不管是输入还是自动填充,在审核完昵称后触发bindnicknamereview
bindnicknamereview | 用户昵称审核完毕后触发,仅在 type 为 “nickname” 时有效,event.detail = { pass, timeout } |
天真的我以为昵称审核完后,触发事件bindnicknamereview,会返回昵称,然而并没有,所以这个方式也不行。
然后我一通搜索,在”表单组件form“文档发现这么一句话
当点击 form 表单中 form-type 为 submit 的 button 组件时,会将表单组件中的 value 值进行提交,需要在表单组件中加上 name 来作为 key。
这样的话获取输入框的内容,就不需要从data获取了,直接我们从bindsubmit这个监听来获取nickname以及其他的参数。
save(e) {
const { nickname, avatar } = e.detail.value;
wx.request({
...
//api逻辑
})
}
//wxml
<!--pages/set-profile/index.wxml 设置用户的头像和昵称-->
<view>
<form bindsubmit="save">
<!-- 头像 -->
<button class="avatar-wrapper" open-type="chooseAvatar" bind:chooseavatar="onChooseAvatar">
<image class="avatar" src="{{avatar}}"></image>
</button>
<!-- 头像隐藏域 -->
<input type="text" name="avatar" value="{{avatar}}" type="text" hidden="true" />
<mp-form>
<mp-cells>
<mp-cell title="昵称">
<input type="nickname" class="weui-input" name="nickname" placeholder="请输入昵称" value="{{nickname}}"/>
</mp-cell>
</mp-cells>
</mp-form>
<button form-type="submit" type="primary" style="margin-top: 100rpx;">保存</button>
</form>
</view>
import config from "../../wxconfig";
const defaultAvatarUrl = "https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0";
Page({
data: {
token: "",
nickname: "",
avatar: "",
userProfile: {},
},
onLoad() {
const token = wx.getStorageSync("token");
const userProfile = wx.getStorageSync("userProfile");
let avatar, nickname;
if (userProfile) {
avatar = userProfile.avatar;
nickname = userProfile.nickname;
} else {
avatar = defaultAvatarUrl;
nickname = "";
}
this.setData({
token,
nickname,
avatar,
userProfile,
});
},
onChooseAvatar(e) {
const { avatarUrl } = e.detail;
wx.uploadFile({
url: config.baseUrl + "/api/v1/upload",
filePath: avatarUrl,
name: "file",
header: {
Authorization: "Bearer " + this.data.token,
},
formData: {
mediaType: "avatar",
},
success: (res) => {
const mydata = JSON.parse(res.data);
if (mydata.status == 1) {
const newAvatar = mydata.data.url;
this.setData({
avatar: newAvatar,
});
} else {
wx.showToast({
title: "上传失败",
icon: "error",
});
}
},
fail: (err) => {
wx.showToast({
title: err.message,
icon: "error",
});
},
});
},
save(e) {
const { nickname, avatar } = e.detail.value;
wx.request({
method: "POST",
url: config.baseUrl + "/api/v1/setprofile",
header: {
Authorization: "Bearer " + this.data.token,
},
data: {
nickname,
avatar,
},
success: (res) => {
if (res.data.status == 1) {
wx.showToast({
title: "保存成功",
icon: "success",
duration: 2000,
});
const userProfile = { ...this.data.userProfile, avatar, nickname };
this.setData({
userProfile,
});
wx.setStorageSync("userProfile", userProfile);
}
},
});
},
});
如果您正在使用 PM2 来管理您的 Node.js 应用程序,并且在服务器重启后您希望应用程序能够自动重新启动,那么您可以通过以下步骤实现:
您可以使用以下命令将 PM2 添加为系统服务:
pm2 startup
这将生成一个命令,您需要复制并在终端中运行,以将 PM2 添加为系统服务。这样,在服务器重启后,PM2 将自动启动。
使用以下命令在 PM2 中启动您的 Node.js 应用程序:
pm2 start app.js
请确保将 app.js
替换为您的应用程序的实际入口文件。
使用以下命令将当前 PM2 应用程序列表保存到文件中:
pm2 save
这将在服务器重启后自动重新加载您的应用程序列表。
总结来说,当您完成以上步骤后,您的 Node.js 应用程序将在服务器重启后自动重新启动。
在hapi.js中,可以使用Joi模块来进行数据验证。Joi是一个Node.js模块,用于验证和转换JavaScript对象。它支持各种数据类型、结构和规则的验证,并提供了易于使用和灵活的API。
以下是一个使用Joi进行验证的示例:
const Hapi = require('@hapi/hapi');
const Joi = require('joi');
const server = Hapi.server({
port: 3000,
host: 'localhost'
});
const validationSchema = Joi.object({
username: Joi.string().alphanum().min(3).max(30).required(),
password: Joi.string().pattern(new RegExp('^[a-zA-Z0-9]{3,30}$')),
email: Joi.string().email({ minDomainSegments: 2, tlds: { allow: ['com', 'net'] } })
});
server.route({
method: 'POST',
path: '/register',
options: {
validate: {
payload: validationSchema
}
},
handler: (request, h) => {
// Handle request...
return 'User registered successfully';
}
});
server.start();
在上述示例中,我们定义了一个Joi验证schema,并将其作为hapi.js路由选项中的payload验证器使用。当客户端发送POST请求到”/register”路由时,hapi.js将首先验证请求的payload是否符合我们定义的schema,如果验证失败,则返回400 Bad Request响应。如果验证通过,则调用路由处理函数来处理请求。
需要注意的是,在上述示例中,我们将Joi验证schema定义为一个独立的变量,这样可以方便地重用它。此外,hapi.js的Joi验证器也支持其他类型的验证,比如params验证和query验证,具体用法与上述示例类似。
在使用hapi.js进行数据验证时,如果出现”Cannot set uncompiled validation rules without configuring a validator”的错误,这通常是因为没有正确配置Joi验证器。
为了正确地使用Joi验证器,需要先将其配置为hapi.js的默认验证器。可以在hapi.js服务器对象的选项中添加”validate”字段来配置Joi验证器。以下是一个示例:
const Hapi = require('@hapi/hapi');
const Joi = require('joi');
const server = new Hapi.Server({
port: 3000,
host: 'localhost',
validate: {
failAction: (request, h, err) => {
throw err;
},
options: {
abortEarly: false
},
schemaOptions: {
abortEarly: false
}
}
});
// ...
在上述示例中,我们将Joi验证器配置为hapi.js的默认验证器,并设置了一些选项。其中,failAction选项指定了验证失败时的处理方式,options选项和schemaOptions选项用于配置Joi验证器的选项。在使用Joi验证器时,需要遵循Joi的规则和语法,以确保验证器能够正常工作。
通常使用ffpmeg转换音视频文件直接用下面的命令
ffpmeg -i input.mp4 output.mp4
视频分辨率通常为以下几种
4k 3840×2160
1080p 1920×1080
720p 1280×720
480p 854×480
360 640×360
根据视频的宽度来设置视频
ffmpeg -i input.mp4 -vf scale=480:-1 output.mp4
根据视频的高度来设置视频
ffmpeg -i input.mp4 -vf scale=-1:720 output.mp4
命令行循环转换文件,达到批量转换的效果
for i in *.avi; do ffmpeg -i "$i" "${i%.*}.mp4"; done
连接数据库服务器操作
mysql -u root -p
取消连接数据库服务器
quit
展示数据库列表
SHOW DATABASES;
创建一个名叫test的数据库
CREATE DATABASE test;
以下是 MySQL 命令行的一些基本操作:
mysql -u <username> -p
命令,然后输入密码。show databases;
命令。use <database_name>;
命令,其中 <database_name>
是要选择的数据库的名称。show tables;
命令。describe <table_name>;
命令,其中 <table_name>
是要查看的表的名称。select * from <table_name>;
命令,其中 <table_name>
是要查询的表的名称。insert into <table_name> (column1, column2, column3) values ('value1', 'value2', 'value3');
命令,其中 <table_name>
是要插入数据的表的名称,column1, column2, column3
是要插入的列的名称,value1, value2, value3
是要插入的值。update <table_name> set column1='value1' where column2='value2';
命令,其中 <table_name>
是要更新的表的名称,column1='value1'
是要更新的列和值,where column2='value2'
是要更新的行的条件。delete from <table_name> where column='value';
命令,其中 <table_name>
是要删除数据的表的名称,where column='value'
是要删除的行的条件。exit
命令或者使用快捷键 Ctrl + D
。刚开始我上tailwind的官网想看看nuxt v3如何安装tailwindcss,安装了一半发现好像不对,tailwind官网的那个教程是nuxt2安装的方式。
搜索之后发现,nuxt官方写了tailwind的插件,网址如下:
nuxtjs的生态tailwind插件 https://tailwindcss.nuxtjs.org/
安装3步搞定