Tarocli开发微信小程序遇到的问题与经验总结
1. 项目背景及疑问
在做微信小程序前,已经上线了一个 h5 项目,h5 中采用的 UI 框架为
Vant
,Vue 版本为 3.x。为了保持用户体验,就采用了Vant Weapp
,但 Taro 中的 vue 版本选择了 2.x 版本。
-
为什么用
Taro
,不用uni-app
?答:下次就用 uni-app。
-
都用 Taro 了,为什么
jsx
不搞起来?答:Taro 主打 react 技术栈,但是 Vant Weapp 是主打 vue 的,我担心在 Taro + Vant Weapp 里面用 jsx,掉进坑里,爬不出来,所以采用了保险点的方式,vue 版本也选择了 2.x 版本,即
Taro + vue2.x + vant-weapp
。 -
Taro 里使用 Vant-Weapp,即使用使用原生第三方组件库开发,不再具有多端转换的能力,那为什么不直接用微信小程序原生开发?
答:项目只要求微信小程序可以使用,不做多端,所以可以放心使用,还有就是 h5 项目里的一些逻辑可以复用。
2. 项目前的准备
2.1 安装及初始化项目
2.1.1 Taro 安装 + 初始化项目
注意: node 环境(>=12.0.0)
- 安装
yarn global add @tarojs/cli
- 初始化
taro init taro_demo
- 安装依赖
# 切换目录
cd taro_demo
# 安装依赖
yarn install
- 修改根目录
package.json
里的scripts
下的dev:weapp
开发启动命令
{
"scripts" : {
- "dev:weapp": "taro build --type weapp"
+ # watch 同时开启压缩
+ "dev:weapp": "set NODE_ENV=production && taro build --type weapp --watch"
}
}
注意:关于这里将NODE_ENV
直接设置为production
,项目的配置就直接使用了生产配置,即config/prod.js
配置,本地开发,配置一些开发设置,难免不方便,我们可以安装cross-env
再配置一个变量,这样就可以解决了。
yarn add cross-env -D
{
"scripts" : {
- "build:weapp": "taro build --type weapp",
+ "build:weapp": "cross-env DEV_MODE_ENV=false taro build --type weapp",
- "dev:weapp": "set NODE_ENV=production && taro build --type weapp --watch"
+ "dev:weapp": "cross-env NODE_ENV=production DEV_MODE_ENV=true taro build --type weapp --watch",
}
}
这样我们就可以根据自己配置的DEV_MODE_ENV
变量来区分是生产还是开发。但这里有一个问题,process.env.DEV_MODE_ENV
这个变量在src
下是访问不到的,config
目录可以正常访问到。要想在 src 下访问自定义 env 变量,需要在config/*.js
里的env
里进行设置,如:
// config/dev.js
module.exports = {
env: {
NODE_ENV: '"development"',
// 添加SERVICES_BASE_URL变量
SERVICES_BASE_URL: '"http://xxx"',
},
};
// config/prod.js
module.exports = {
env: {
NODE_ENV: '"production"',
// 这里添加的 DEV_MODE_ENV 就起作用了,进行生产、开发区分,不用每次手动去改了
SERVICES_BASE_URL:
process.env.DEV_MODE_ENV === "true" ? "http://xxx" : "https://xxx",
},
};
// 代码里访问`process.env.SERVICES_BASE_URL`是可以正常获取到的
- 启动开发命令,成功后,即可看到根目录有新生成的
dist
目录
yarn run dev:weapp
2.1.2 微信开发者工具
-
下载微信开发者工具
-
选择刚刚的
dist
进行打开,不出意外,可以正常预览了。
2.2 项目中主要 package version
后面出现的问题,都是基于这些版本。
package | version |
---|---|
Taro | 3.3.7 |
vant weapp | 1.9.2 |
echarts | 5.1.2 |
3. Taro 中使用 Vant Weapp
3.1 修改postcss
配置,不转换 vant 的样式
// config/index.js
const config = {
mini: {
enableSourceMap: false, // 用于控制是否生成 js、css 对应的 sourceMap
// http://taro-docs.jd.com/taro/docs/vant
postcss: {
pxtransform: {
enable: true,
config: {
selectorBlackList: [/van-/],
},
},
url: {
enable: true,
config: {
limit: 1024,
},
},
cssModules: {
enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
config: {
namingPattern: "module", // 转换模式,取值为 global/module
generateScopedName: "[name]__[local]___[hash:base64:5]",
},
},
},
},
};
3.2 配置小程序原生文件和引用 vant 的组件
3.2.1 根据文档,使用 vant 需要这样做
// config/index.js
const config = {
// ...
copy: {
patterns: [
// 前面3个是基础的
{
from: "src/components/vant-weapp/dist/wxs",
to: "dist/components/vant-weapp/dist/wxs",
},
{
from: "src/components/vant-weapp/dist/common/style",
to: "dist/components/vant-weapp/dist/common/style",
},
{
from: "src/components/vant-weapp/dist/common/index.wxss",
to: "dist/components/vant-weapp/dist/common/index.wxss",
},
// 需要用到vant哪个组件就引入,比如引入button
{
from: `src/components/vant-weapp/dist/button/index.wxs`,
to: `dist/components/vant-weapp/dist/button/index.wxs`,
},
{
from: "src/components/vant-weapp/dist/button/index.wxml",
to: "dist/components/vant-weapp/dist/button/index.wxml",
},
],
options: {},
},
};
// 页面的 index.config.js 中引入或者全局 src/app.config.js中的引入
export default {
navigationBarTitleText: "首页",
usingComponents: {
"van-button": "../../components/vant-weapp/dist/button/index",
},
};
发现没,这不是一堆重复动作吗,需要用到 vant 组件,就必须要到两个地方配置一下,很难受。
3.2.2 升级改造,优化引入步骤
- 根目录创建
vantComponentConf.js
文件这样只需每次修改 vantComponentConf 文件,组件引入就生效了,不用重复改动,当然有能力可以直接使用 babel,写一个 loader 解决
注意:
- 每次添加新的 vant 组件,项目还是得重启,不能像
vite
那样潇洒,改配置文件也能马上自动重启生效 - 部分 vant 组件,引入重启后还是提示缺少其它组件,那就再把缺少的组件添加到 vantComponentConf 里去,如 button 组件就依赖 icon 和 loading,单独引入 button 是不行的。
const vantComponetNames = ["button", "icon", "loading"];
module.exports = vantComponetNames;
- 修改
config/index.js
文件
+ const path = require("path");
+ const fs = require("fs");
+ const vantComponetNames = require("../vantComponentConf");
+
+ const handleGetPatterns = (keyArr) => {
+ // 这些为公共组件
+ const defaultArr = [
+ {
+ from: "src/components/vant-weapp/dist/wxs",
+ to: "dist/components/vant-weapp/dist/wxs",
+ },
+ {
+ from: "src/components/vant-weapp/dist/common/style",
+ to: "dist/components/vant-weapp/dist/common/style",
+ },
+ {
+ from: "src/components/vant-weapp/dist/common/index.wxss",
+ to: "dist/components/vant-weapp/dist/common/index.wxss",
+ },
+ ];
+
+ const componentArr = keyArr
+ .map((componentName) => {
+ // 同步检测这个文件是否存在
+ // 因为vant weapp部分组件文件下的不存在 wxs 文件
+ const componentPath = path.resolve(
+ __dirname,
+ `../src/components/vant-weapp/dist/${componentName}/index.wxs`
+ );
+
+ const isState = fs.statSync(componentPath, { throwIfNoEntry: false });
+
+ return [
+ {
+ from: `src/components/vant-weapp/dist/${componentName}/index.${
+ isState ? "wxs" : "wxss"
+ }`,
+ to: `dist/components/vant-weapp/dist/${componentName}/index.${
+ isState ? "wxs" : "wxss"
+ }`,
+ },
+ {
+ from:
+ "src/components/vant-weapp/dist/" + componentName + "/index.wxml",
+ to:
+ "dist/components/vant-weapp/dist/" + componentName + "/index.wxml",
+ },
+ ];
+ })
+ .flat(Infinity);
+
+ return [...defaultArr, ...componentArr];
+ };
const config = {
copy: {
+ // http://taro-docs.jd.com/taro/docs/vant
+ patterns: handleGetPatterns(vantComponetNames),
options: {},
},
}
- 修改
src/app.config.js
文件
+ const vantComponetNames = require("../vantComponentConf");
+
+ const getVantComponetConf = (arr) => {
+ const result = {};
+ arr.forEach((key) => {
+ result[`van-${key}`] = `./components/vant-weapp/dist/${key}/index`;
+ });
+
+ return result;
+ };
export default {
usingComponents: {
+ ...getVantComponetConf(vantComponetNames),
},
}
4. 关于使用 Vant 遇到的一些问题
4.1 部分 vant 组件的插槽不能正确显示
如下search
组件不能正确显示 slot 内容
<view>
<van-search use-action-slot="true" placeholder="请输入门店名称搜索...">
<view slot="action"> 搜索 </view>
</van-search>
</view>
解决:
必须使用 taro 提供的slot-view组件,React 中使用Slot
组件
<template>
<view>
<van-search use-action-slot="true" placeholder="请输入门店名称搜索...">
<slot-view name="action">
<text>搜索</text>
</slot-view>
</van-search>
</view>
</template>
slot 里的内容正确显示了
4.2 vant-search
获取不到输入的内容
<template>
<view>
<van-search
:value="searchVal"
use-action-slot="true"
>
<slot-view name="action">
<text @tap.stop="onSearch">搜索</text>
</slot-view>
</van-search>
</view>
</template>
<script>
export default {
data() {
return {
searchVal: "",
}
},
methods: {
onSearch() {
// 这里并不会打印出实时的输入值
console.log("this.searchVal", this.searchVal);
}
},
}
</script>
解决:
vant-search
并不会自己同步更新数据,需要手动添加change
事件更新
<template>
<view>
<van-search
:value="searchVal"
use-action-slot="true"
+ @change="onChange"
>
<slot-view name="action">
<text @tap.stop="onSearch">搜索</text>
</slot-view>
</van-search>
</view>
</template>
<script>
export default {
data() {
return {
searchVal: "",
}
},
methods: {
+ onChange(e) {
+ this.searchVal = e.detail;
+ },
onSearch() {
console.log("this.searchVal", this.searchVal);
}
},
}
</script>
4.3 使用van-field
组件时,vue 中的 computed 的值不能触发响应更新
计算属性computed
里定义的 submitBtnDisabled,里面依赖的值改变了,但是没触发响应更新。不用怀疑,肯定不是 vue 的问题
<template>
<view class="phoneLoginWrap">
<form @submit="handleSubmit">
<van-cell-group>
<van-field
v-model="user"
:required="true"
name="user"
label="账号:"
placeholder="请输入账号"
title-width="4em"
/>
<van-field
v-model="password"
:required="true"
name="password"
type="password"
label="密码:"
placeholder="请输入密码"
/>
</van-cell-group>
<van-button type="info" form-type="submit" :block="true" :disabled="submitBtnDisabled">登录</van-button>
</form>
</view>
</template>
<script>
export default {
data() {
return {
user: "",
password: ""
}
},
computed: {
// 只有首次进入页面时触发,后面不被触发
// 导致登录按钮永远是disabeld状态
submitBtnDisabled: function () {
return this.user !== '' && this.password !== '' ? false : true;
}
},
methods: {
handleSubmit(e) {
// vant-button 即使disabled为true,依然可以进入这里
// UI样式生效了,但事件依然可以被触发
// 所以这里要加判断
if (this.submitBtnDisabled) return;
console.log("login!!!", e)
}
}
}
</script>
解决:
其实跟上面的vant-search
一个毛病,需要自己手动给vant-field
加上change
事件,这样在改变输入框的值的时候,按钮的 diabled 属性可以动态更新
<template>
<view class="phoneLoginWrap">
<form @submit="handleSubmit">
<van-cell-group>
<van-field
v-model="user"
:required="true"
name="user"
label="账号:"
placeholder="请输入账号"
+ @change="(...args) => handleFieldChange.call(this, 'user', ...args)"
/>
<van-field
v-model="password"
:required="true"
name="password"
type="password"
label="密码:"
placeholder="请输入密码"
+ @change="(...args) => handleFieldChange.call(this, 'password', ...args)"
/>
</van-cell-group>
<van-button type="info" form-type="submit" :block="true" :disabled="submitBtnDisabled">登录</van-button>
</form>
</view>
</template>
<script>
export default {
name: 'PhoneNumLogin',
data() {
return {
user: "",
password: ""
}
},
computed: {
submitBtnDisabled: function () {
return this.user !== '' && this.password !== '' ? false : true;
}
},
methods: {
+ handleFieldChange(type, e) {
+ const val = e.detail.trim();
+ // 这里手动更新data的值
+ if (type === 'user') {
+ this.user = val;
+ } else {
+ this.password = val;
+ }
},
handleSubmit(e) {
if (this.submitBtnDisabled) return;
console.log("login!!!", e)
}
}
}
</script>
4.4 vant 组件使用的时候控制台大片警告
原因: 微信基础库修改了校验逻辑,所以才出现 slot 没找到或者 properties 类型不对等警告信息
5. 关于使用 ec-canvas
echarts 遇到的一些问题
5.1 echarts 体积过大问题
解决:
- echarts 在线定制下载
- 一定要在线选择压缩,下载的文件放在 ec-canvas/echarts.js,然后一定要重命名为echarts.js
5.2 ec-canvas 报错 t.addEventListener is not a function
TypeError: t.addEventListener is not a function
解决:
在 wx-canvas.js 文件中添加:
// wx-canvas.js
export default class WxCanvas {
constructor(ctx, canvasId, isNew, canvasNode) {
// ...
}
+ // 新增空函数,修复调用 echarts.init 时报错
+ addEventListener() {}
}
5.3 ec-canvas 报错 this.Chart.init is not a function
TypeError: this.Chart.init is not a function
解决:
Taro 3.0 以上需要用 selectComponent 获取子组件实例
import Taro, { getCurrentInstance } from "@tarojs/taro";
function initChart(el = "#canvasId") {
const currentIns = getCurrentInstance();
currentIns.page.selectComponent(el).init((canvas, width, height) => {
const sysInfo = Taro.getSystemInfoSync();
const chart = echarts.init(canvas, null, {
width: width,
height: height,
devicePixelRatio: sysInfo.devicePixelRatio || sysInfo.pixelRatio, // 像素
});
canvas.setChart(chart);
var option = {
// ...
};
chart.setOption(option);
return chart;
});
}
5.4 ec-canvas 接口请求数据后后异步渲染或 socket 获取数据实时动态渲染
<template>
<view style="widh: 100%; height: 300px;">
<ec-canvas id="yearLineChart" canvas-id="month-line-chart" :ec="yearChart" />
</view>
</template>
<script>
import Taro from '@tarojs/taro';
import * as echarts from '@/src/components/echarts-for-weixin-master/ec-canvas/echarts';
function setOption(chart) {
var option = {
// ...
};
chart.setOption(option);
}
export default {
data() {
return {
yearChart: {
// 将 lazyLoad 设为 true 后,需要手动初始化图表
lazyLoad: true
}
}
},
methods: {
// 初始化echarts
initChart(el, data) {
const currentIns = Taro.getCurrentInstance();
currentIns.page.selectComponent(el)
.init((canvas, width, height) => {
const sysInfo = Taro.getSystemInfoSync();
const chart = echarts.init(canvas, null, {
width: width,
height: height,
devicePixelRatio: sysInfo.devicePixelRatio || sysInfo.pixelRatio // 像素
});
setOption(chart, data);
// 注意这里一定要返回 chart 实例,否则会影响事件处理等
return chart;
});
},
// ajax后台获取数据
getData() {
// ....
// 假设data从后台返回
const data = {}
this.initChart('year', '#yearLineChart', data);
}
},
onShow() {
this.getData();
}
}
</script>
5.5 导入 echart 包后提示 it exceeds the max of 500KB
命令行警告,导致每次ctrl + s
保存代码,微信开发者工具那边更新缓慢
[BABEL] Note: The code generator has deoptimised the styling of "unknown" as it exceeds the max of "500KB"
解决:
- config/index.js 添加 exclude 排除项
module.exports = {
// ...
mini: {
// ...
compile: {
exclude: [
path.resolve(
__dirname,
"../src/components/echarts-for-weixin-master/ec-canvas/echarts.js"
),
],
},
},
};
- 在 babel 配置文件中添加compact: false,默认为 auto
module.exports = {
presets: [
[
"taro",
{
framework: "vue",
ts: false,
},
],
],
compact: false,
};
5.6 使用 ec-canvas 后,小程序桌面端打开一片显示空白
造成空白的原因,其实是已经报错了
有说是给ec-canvas
标签添加force-use-old-canvas="true"
属性为 true 后,既可以。但是我这里 echarts 用的是5.1.2
版本,实测没生效。
解决:
windows 终端小程序不支持 canvas2d,修改为在 windows 终端采用旧版 canvas
最新版本有无修复桌面端打开是否成功,我这里没有验证。我直接对着这个 PR 修改源码了,实测有效。
// 修改echarts-for-weixin-master/ec-canvas/ec-canvas.js
Component({
methods: {
- init: function (callback) {
+ init: async function (callback) {
const version = wx.getSystemInfoSync().SDKVersion;
const canUseNewCanvas = compareVersion(version, "2.9.0") >= 0;
const forceUseOldCanvas = this.data.forceUseOldCanvas;
- const isUseNewCanvas = canUseNewCanvas && !forceUseOldCanvas;
+ // const isUseNewCanvas = canUseNewCanvas && !forceUseOldCanvas;
+ // 修复桌面端微信打开,echarts一片空白,控制台报错
+ const { platform } = await wx.getSystemInfo();
+ let isUseNewCanvas = canUseNewCanvas && !forceUseOldCanvas;
+ // 直接通过正则判断,如果是windows桌面端微信打开
+ // 将isUseNewCanvas的值设为false
+ if (platform && /windows/i.test(platform)) {
+ isUseNewCanvas = false;
+ }
this.setData({ isUseNewCanvas });
// ...
}
}
})
6. 关于 Taro 的一些问题
6.1 项目体积过大,使用微信开发者工具无法预览,要进行分包处理
注意: 配置在tabBar
中的页面不能分包写到subpackages
中去
- 分包前:
// src/app.config.js
export default {
pages: ["pages/foo1/index", "pages/foo2/index", "pages/foo3/index"],
};
- 分包后:
// src/app.config.js
export default {
pages: ["pages/foo1/index", "pages/foo2/index"],
subpackages: [
{
root: "pages/foo3",
pages: ["index"],
},
],
};
6.2 Taro.eventCenter 全局消息的问题
6.2.1 页面路由跳转 Taro.eventCenter 全局消息首次监听不生效
问题描述
- 1.路由 A 页面点击确认按钮后 发送全局消息事件 Taro.eventCenter.trigger('getInfo', data)
- 2.然后跳转到路由 B 页面 B 页面在 componentWillMount 页面被加载的时候 监听 Taro.eventCenter.on('getInfo', e => { }) 监听不到该事件
解决:
- 手动在父页面手动延迟 trigger(不够优雅)
- 使用 vuex
6.2.2 Tabbar 之间的通信,Taro.eventCenter 通信首次不触发
原因:跟上面一样,事件已经被触发,但是后面页面还没被初始化,不支持历史消息订阅
解决:
- 手动在 tab foo1 页面 setTimeout 手动延迟 trigger,然后 tab foo2 就可以监听到了(不优雅)
Taro.switchTab({
url: "/pages/foo1/index",
complete: () => {
// 这样在foo2页面的onShow里就可以监听到了
setTimeout(() => {
Taro.eventCenter.trigger(eventTypes.SENT_CUS_ID, 10086);
}, 800);
},
});
- 不使用原生
tab
,自己另造一个,就摆脱了这个局限 - 使用 vuex(打包增加体积)
- 既然都 vue 了,
eventBus
挺好
import Vue from "vue";
import * as types from "./eventTypes";
// 特殊的eventBus
// https://segmentfault.com/a/1190000012808179
const bus = new Vue({
data() {
return {
// 定义数据
cus_id: null,
};
},
created() {
// 绑定监听
this.$on(types.CHANGE_CUS_ID, (id) => {
console.log("CHANGE_SHOP_ID==>");
this.cusId = id;
});
},
});
export default bus;
export { types };
- vue 中的其他通信方式...
6.3 sitemap 索引情况提示
控制台警告
[sitemap 索引情况提示] 根据 sitemap 的规则[0],当前页面 [pages/overview/index] 将被索引
解决:
修改小程序项目配置文件 project.config.json
的 setting 中配置字段 checkSiteMap 为 false
{
"setting": {
"checkSiteMap": false
}
}
6.4 生产打包去除 console
- 安装
注意:
最新版本的 terser 使用会报错
TypeError: Cannot read property 'javascript' of undefined
降级安装 4.x 版本
yarn add terser-webpack-plugin@4.2.3 -D
-
config/prod.js
配置文件修改
module.exports = {
mini: {
// http://taro-docs.jd.com/taro/docs/config-detail#miniwebpackchain
webpackChain(chain, webpack) {
chain.plugin("terser").use(TerserPlugin, [
{
// https://www.npmjs.com/package/terser-webpack-plugin#terseroptionsco
terserOptions: {
mangle: true,
compress: {
// https://swc.rs/docs/configuration/minification
drop_console: true,
drop_debugger: true,
},
output: {
// https://drylint.com/Webpack/terser-webpack-plugin.html#%E5%AE%89%E8%A3%85
ascii_only: true, // 转义字符串和正则中的 Unicode 字符
},
},
},
]);
},
},
};
6.5 Taro.onSocketError 返回的错误信息“未完成的操作”,拿不到真实的错误
wx.onSocketError 提示未完成操作是什么意思?
未解决
6.6 微信小程序体验版报错 request fail
安卓上报错信息,换ios可以看到具体报错信息
request:fail -2:net::ERR_FAILED
解决:
- 排查服务器域名配置,严格按照这个规范进行配置
- 检查证书配置,nginx 配中间证书
6.7 微信小程序新版本更新检测,自动更新
export default {
onReady() {
if (!Taro.canIUse("getUpdateManager")) {
Taro.showModal({
title: "提示",
content: "当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试",
showCancel: false,
});
return;
}
// https://developers.weixin.qq.com/miniprogram/dev/api/base/update/UpdateManager.html
const updateManager = Taro.getUpdateManager();
updateManager.onCheckForUpdate((res) => {
// 请求完新版本信息的回调
if (res.hasUpdate) {
updateManager.onUpdateReady(function () {
Taro.showModal({
title: "更新提示",
content: "新版本已经准备好,是否重启应用?",
success: function (res) {
if (res.confirm) {
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
updateManager.applyUpdate();
}
},
});
});
updateManager.onUpdateFailed(function () {
// 新版本下载失败
Taro.showModal({
title: "更新提示",
content: "新版本已上线,请删除当前小程序,重新搜索打开",
});
});
}
});
},
};
6.8 Taro 中无法使用 css 变量问题
解决:
如果是 vue3,就有现成的解决方案,vue3 单文件组件样式特性
// 通过在顶层元素设置 style 来解决
import './style.css';
const style = { '--primary-color': 'red' }
return <View style={style} className='container'>container elemet</View>
/* styles.css */
.container {
color: var(--primary-color);
}
6.9 关于 Taro 使用原生 HTML 标签
其实还是建议使用小程序原生标签,不推荐 html 标签,怕掉进坑。
- 安装
yarn add @tarojs/plugin-html
- 配置插件
// config/index.js
config = {
// ...
plugins: ['@tarojs/plugin-html']
}
- 使用
<template>
<div>Hello World!</div>
</template>
7. 参考资料
- Taro 官方文档
- 微信小程序官方文档
- Vant Weapp 官方文档
推荐阅读
-
微信小程序中Echarts的动态应用与图表层级问题解决指南
-
Tarocli开发微信小程序遇到的问题与经验总结
-
智联招聘发布第三季度平均薪酬报告;价值13亿美元的Metaverse日活跃用户仅38人;统一充电接口或让苹果一年损失数百亿美元 | EA周报 - 热点大事件 微信推出刷掌付小程序,开启全新支付模式 据悉,微信已上线 "微信刷掌付 "小程序,可以为用户刷掌付增加更便捷的管理方式,但刷掌付功能需要在刷掌设备上开通。刷掌付是继密码支付、指纹支付、刷脸支付之后,微信的又一新型支付方式。据悉,目前微信支付已在深圳部分商户接入刷掌付设备进行测试,用户可通过刷掌纹支付订单。刷掌纹设备由微信支付提供,设备上设有显示屏和掌纹识别区,用户开通微信刷掌纹支付功能后,只需在掌纹识别区扫描,即可完成商品支付,相比传统的密码支付和指纹支付,更加便捷。(星球科技) 微软多项云服务落户中国新数据中心 2022年10月13日,微软年度技术大会Ignite 2022和Ignite China中国技术峰会同步开启在线直播。面对中国市场日益增长的客户需求,微软宣布,Azure、Dynamics Power Platform等多项服务已在北上广三地数据中心落地,提升在中国市场的服务能力;世纪互联运营的Office 365上的Teams服务和世纪互联运营的Microsoft 365服务将于2023年上半年正式上线,为中国市场带来更全面、更优质的本地化服务体验和技术保障。 IBM宣布将红帽存储并入存储业务部 根据IBM与红帽的协议,IBM将成为Ceph基金会的主要赞助商,该基金会的成员合作推动Ceph开源项目的创新、开发、营销和社区活动。红帽OpenStack客户仍可从红帽及其合作伙伴处购买红帽Ceph存储,而拥有现有订购服务的红帽OpenShift和红帽OpenStack客户将能够在不改变与红帽关系的情况下,根据需要维护和扩展其存储足迹。 扎克伯格谈新款1万美元VR头显:成本价,我们不会像苹果那样定高价 元CEO扎克伯格在接受采访时谈到了公司新发布的Quest Pro新款VR头显的价格,他表示1499.99美元的定价只是 "性价比",让更多人通过购买硬件来体验元宇宙。扎克伯格还借此机会挖苦了竞争对手苹果公司,称苹果公司对该设备的定价 "已经到了极限"。他说:"通常,人们制造硬件,然后想从中获利。例如,苹果公司就是这样做的,制造硬件,然后尽可能多地收费。他说,公司还计划推出 Quest 3,售价在 300 美元到 500 美元之间。 智联招聘发布招聘薪资报告,第三季度全国平均薪资为10168美元/月
-
如何解决 uniapp 开发中按需注入启用组件的问题 微信小程序 - 问题解决方案
-
uniapp微信小程序实战记:探索Pinia状态管理的持久化问题与解决经验
-
搞定微信小程序开发工具基础库下载失败:DNS问题详解与解决方案
-
微信小程序开发初体验:小白的心路历程与体会
-
微信、企业微信和微信小程序开发中常见问题的全面总结
-
使用JavaWeb、SSM和Vue开发微信小程序生鲜云订单零售系统的实操指南与详细步骤-Lun文目录
-
使用JavaWeb、SSM和Vue开发基于微信小程序的在线商城系统的设计与实现-论文目录