深度解析HarmonyOS SDK实况窗服务源码,Get不同场景下的多种模板
HarmonyOS SDK实况窗服务(Live View Kit)作为一个实时呈现应用服务信息变化的小窗口,遍布于设备的各个使用界面,它的魅力在于将复杂的应用场景信息简洁提炼并实时刷新,在不影响当前其他应用操作的情况下,时刻向用户展示最新的信息动态,用户也可以点击实况窗卡片或胶囊进入应用落地页查看详细信息,享受来自应用的高效信息同步服务。
实况窗服务为不同场景定制了多样化的卡片模板,包括进度可视化模板、强调文本模板、左右文本模板、赛事比分模板、导航模板,除了这5种卡片形态的模板外,实况窗还有实况胶囊和实况计时器两种形态。下面,本文将详细展示这些模板,介绍其适用的场景,并讲解模板的具体实现步骤。
开发准备
在创建本地实况窗之前,需要先完成基本的准备工作,并开通实况窗服务权益。开通实况窗权益大致分为5个步骤,详细的申请步骤可参考实况窗服务的开发指南。
开发步骤
下面将以在本地创建、更新和结束实况窗为例,展示具体的开发步骤。
1.导入liveViewManager。
在创建本地实况窗前,需要在项目中导入liveViewManager,并新建实况窗控制类,构造isLiveViewEnabled()方法,用于校验实况窗开关是否打开。打开实况窗开关是创建实况窗的前提条件。示例代码如下:
import { liveViewManager } from '@kit.LiveViewKit';
export class LiveViewController {
private static async isLiveViewEnabled(): Promise<boolean> {
return await liveViewManager.isLiveViewEnabled();
}
}
2.创建实况窗。
实况窗根据扩展区不同共有5种样式模板:进度可视化模板、强调文本模板、左右文本模板、赛事比分模板和导航模板。
进度可视化模板
进度可视化模板可适用于打车、外卖等需要呈现完整进程及当前节点的场景,通过进度可视化模板的实况窗,用户可一眼查看应用的服务进程和实时变化。这里以即时配送场景为例,展示具体的示例代码。
在构建LiveViewController后,需要在代码中初始化LiveViewController并调用liveViewManager.startLiveView()方法创建实况窗。其中event的取值为DELIVERY则代表即时配送场景,若取值为TAXI则表示出行打车场景。
import { liveViewManager } from '@kit.LiveViewKit';
import { Want, wantAgent } from '@kit.AbilityKit';
export class LiveViewController {
public async startLiveView(): Promise<liveViewManager.LiveViewResult> {
// 校验实况窗开关是否打开
if (!LiveViewController.isLiveViewEnabled()) {
throw new Error("Live view is disabled.");
}
// 创建实况窗
const defaultView = await LiveViewController.buildDefaultView();
return await liveViewManager.startLiveView(defaultView);
}
private static async buildDefaultView(): Promise<liveViewManager.LiveView> {
return {
// 构造实况窗请求体
id: 0, // 实况窗ID,开发者生成。
event: "DELIVERY", // 实况窗的应用场景。DELIVERY:即时配送(外卖、生鲜)
liveViewData: {
primary: {
title: "骑手已接单",
content: [
{ text: "距商家 " },
{ text: "300 ", textColor: "#FF007DFF" },
{ text: "米 | " },
{ text: "3 ", textColor: "#FF007DFF" },
{ text: "分钟到店" }
], // 所有文本仅能设置为一种颜色,不设置textColor时,默认展示#FF000000
keepTime: 15,
clickAction: await LiveViewController.buildWantAgent(),
layoutData: {
layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_PROGRESS,
progress: 40,
color: "#FF317AF7",
backgroundColor: "#f7819ae0",
indicatorType: liveViewManager.IndicatorType.INDICATOR_TYPE_UP,
indicatorIcon: "indicator.png", // 进度条指示器图标,取值为
"/resources/rawfile"路径下的文件名
lineType: liveViewManager.LineType.LINE_TYPE_DOTTED_LINE,
nodeIcons: ["icon_1.png", "icon_2.png", "icon_3.png"] // 进度条每个节点图标,
取值为"/resources/rawfile"路径下的文件名
}
}
}
};
}
private static async isLiveViewEnabled(): Promise<boolean> {
return await liveViewManager.isLiveViewEnabled();
}
private static async buildWantAgent(): Promise<Want> {
const wantAgentInfo: wantAgent.WantAgentInfo = {
wants: [
{
bundleName: 'xxx.xxx.xxx', // 应用实际bundleName
abilityName: 'EntryAbility'
} as Want
],
operationType: wantAgent.OperationType.START_ABILITIES,
requestCode: 0,
wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
};
const agent = await wantAgent.getWantAgent(wantAgentInfo);
return agent;
}
}
强调文本模板
强调文本模板适用于取餐、排队等需要强调部分文本信息的场景。通过强调文本模板实况窗,用户可以快速获取取餐码、排号情况等重要信息,这里以取餐场景为例,展示具体的示例代码。
在强调文本模板中,event取值为PICK_UP则代表取餐场景,若取值为QUEUE则代表排队场景。
import { liveViewManager } from '@kit.LiveViewKit';
import { Want, wantAgent } from '@kit.AbilityKit';
export class LiveViewController {
public async startLiveView(): Promise<liveViewManager.LiveViewResult> {
// 校验实况窗开关是否打开
if (!LiveViewController.isLiveViewEnabled()) {
throw new Error("Live view is disabled.");
}
// 创建实况窗
const defaultView = await LiveViewController.buildDefaultView();
return await liveViewManager.startLiveView(defaultView);
}
private static async buildDefaultView(): Promise<liveViewManager.LiveView> {
return {
// 构造实况窗请求体
id: 0, // 实况窗ID,开发者生成。
event: "PICK_UP", // 实况窗的应用场景。PICK_UP:取餐。
liveViewData: {
primary: {
title: "餐品已备好",
content: [
{ text: "请前往", textColor: "#FF000000" },
{ text: "XXX店取餐", textColor: "#FF000000" }
],
keepTime: 15,
clickAction: await LiveViewController.buildWantAgent(),
layoutData: {
layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_PICKUP,
title: "取餐码",
content: "72988",
underlineColor: "#FF0A59F7",
descPic: "coffee.png"
}
}
}
};
}
... ...
}
左右文本模板
左右文本模板适用于高铁、航班等左右信息对称的场景,通过该模板,用户可以快速获取始发地、目的地、开始和结束时间等出行信息。这里以高铁列车票场景为例,展示具体的示例代码。
在左右文本模板中,event取值为TRAIN则代表高铁/火车场景,若取值为FLIGHT则代表航班场景。
import { liveViewManager } from '@kit.LiveViewKit';
import { Want, wantAgent } from '@kit.AbilityKit';
export class LiveViewController {
public async startLiveView(): Promise<liveViewManager.LiveViewResult> {
// 校验实况窗开关是否打开
if (!LiveViewController.isLiveViewEnabled()) {
throw new Error("Live view is disabled.");
}
// 创建实况窗
const defaultView = await LiveViewController.buildDefaultView();
return await liveViewManager.startLiveView(defaultView);
}
private static async buildDefaultView(): Promise<liveViewManager.LiveView> {
return {
// 构造实况窗请求体
id: 0, // 实况窗ID,开发者生成。
event: "TRAIN", // 实况窗的应用场景。TRAIN:高铁/火车。
liveViewData: {
primary: {
title: "列车检票提醒",
content: [
{ text: "检票口 " },
{ text: "6B ", textColor: "#FF007DFF" },
{ text: "| 座位 " },
{ text: "03车 12F", textColor: "#FF007DFF" }
],// 所有文本仅能设置为一种颜色,不设置textColor时,默认展示#FF000000
keepTime: 15,
clickAction: await LiveViewController.buildWantAgent(), // 点击实况窗默认动作。
layoutData: {
layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_FLIGHT,
firstTitle: "09:00",
firstContent: "上海虹桥",
lastTitle: "14:20",
lastContent: "汉口",
spaceIcon: "icon.png",
isHorizontalLineDisplayed: true,
additionalText: "以上信息仅供参考" // 扩展区底部内容,仅可用于左右文本模板。
}
}
}
};
}
... ...
}
赛事比分模板
赛事比分模板适用于竞技比赛的场景,通过该模板,用户可以快速获取比赛队伍、当前比分、场次等比赛信息。
在赛事比分模板中,SCORE代表赛事比分场景。
import { liveViewManager } from '@kit.LiveViewKit';
import { Want, wantAgent } from '@kit.AbilityKit';
export class LiveViewController {
public async startLiveView(): Promise<liveViewManager.LiveViewResult> {
// 校验实况窗开关是否打开
if (!LiveViewController.isLiveViewEnabled()) {
throw new Error("Live view is disabled.");
}
// 创建实况窗
const defaultView = await LiveViewController.buildDefaultView();
return await liveViewManager.startLiveView(defaultView);
}
private static async buildDefaultView(): Promise<liveViewManager.LiveView> {
return {
// 构造实况窗请求体
id: 0, // 实况窗ID,开发者生成。
event: "SCORE", // 实况窗的应用场景。SCORE:赛事比分。
liveViewData: {
primary: {
title: "第四节比赛中",
content: [
{ text: "XX VS XX" },
{ text: " | ", textColor: "#f7b7b1b3"},
{ text: "小组赛第五场"}
],
keepTime: 1,
clickAction: await LiveViewController.buildWantAgent(),
layoutData: {
layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_SCORE,
hostName: "队名A",
hostIcon: "host.png",
hostScore: "110",
guestName: "队名B",
guestIcon: "guest.png",
guestScore: "102",
competitionDesc: [
{ text: "●", textColor: "#FFFF0000" },
{ text: "Q4" }
],
competitionTime: "02:16",
isHorizontalLineDisplayed: true
}
}
}
};
}
... ...
}
导航模板
导航模板适用于出行导航场景。通过该模板,用户可以快速获取所需导航的目的地大致方位信息。在导航模板中,event取值为NAVIGATION则代表导航场景。
import { liveViewManager } from '@kit.LiveViewKit';
import { Want, wantAgent } from '@kit.AbilityKit';
export class LiveViewController {
public async startLiveView(): Promise<liveViewManager.LiveViewResult> {
// 校验实况窗开关是否打开
if (!LiveViewController.isLiveViewEnabled()) {
throw new Error("Live view is disabled.");
}
// 创建实况窗
const defaultView = await LiveViewController.buildDefaultView();
return await liveViewManager.startLiveView(defaultView);
}
private static async buildDefaultView(): Promise<liveViewManager.LiveView> {
return {
// 构造实况窗请求体
id: 0, // 实况窗ID,开发者生成。
event: "NAVIGATION", // 实况窗的应用场景。NAVIGATION:导航。
liveViewData: {
primary: {
title: "178米后左转",
content: [
{ text: "去往", textColor: "#FF000000" },
{ text: " 南京东路", textColor: "#FF000000" }
],
keepTime: 15,
clickAction: await LiveViewController.buildWantAgent(),
layoutData: {
layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_NAVIGATION,
currentNavigationIcon: "navigation.png",
navigationIcons: ["left.png","straight.png","straight.png","right.png"]
}
}
}
};
}
... ...
}
实况胶囊
实况胶囊是在设备熄屏和状态栏中展示的区别于卡片态的另一种实况形态,胶囊内需显示最精简、最重要的内容,保证用户一瞥即得重要信息。并且,胶囊形态各模板参数固定,与创建实况窗时的模板类型无关。
在同步创建实况窗胶囊时,需要在liveViewManager.LiveView结构体中携带胶囊所需的参数capsule,不同胶囊类型携带不同的参数。可创建的胶囊类型有:文本胶囊、计时器胶囊和进度胶囊。这里以文本胶囊为例,展示具体的示例代码。
import { liveViewManager } from '@kit.LiveViewKit';
import { Want, wantAgent } from '@kit.AbilityKit';
export class LiveViewController {
public async startLiveView(): Promise<liveViewManager.LiveViewResult> {
// 校验实况窗开关是否打开
if (!LiveViewController.isLiveViewEnabled()) {
throw new Error("Live view is disabled.");
}
// 创建实况窗
const defaultView = await LiveViewController.buildDefaultView();
return await liveViewManager.startLiveView(defaultView);
}
private static async buildDefaultView(): Promise<liveViewManager.LiveView> {
return {
// 构造实况窗请求体
id: 0, // 实况窗ID,开发者生成。
event: "DELIVERY", // 实况窗的应用场景。DELIVERY:即时配送(外卖、生鲜)。
liveViewData: {
primary: {
title: "餐品待支付",
content: [
{ text: "咖啡 ", textColor: "#FF000000" },
{ text: "等2件商品", textColor: "#FF000000" }
],
keepTime: 15,
clickAction: await LiveViewController.buildWantAgent(),
layoutData: {
layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_PICKUP,
title: "待支付金额",
content: "25.5元",
underlineColor: "#FF0A59F7",
descPic: "coffee.png"
}
},
// 实况胶囊相关参数
capsule: {
type: liveViewManager.CapsuleType.CAPSULE_TYPE_TEXT,
status: 1,
icon: "capsule_store.png",
backgroundColor: "#ff0676e7",
title: "待支付"
}
}
};
}
... ...
}
实况窗计时器
实况窗计时器适用于排队、抢票等场景。开发者若需要使用实况窗计时器,则需在liveViewManager.LiveView结构体中的配置timer字段,并在当前支持的字段中使用占位符:${placeholder.timer}。
具体的示例代码如下:
import { liveViewManager } from '@kit.LiveViewKit';
import { Want, wantAgent } from '@kit.AbilityKit';
export class LiveViewController {
public async startLiveView(): Promise<liveViewManager.LiveViewResult> {
// 校验实况窗开关是否打开
if (!LiveViewController.isLiveViewEnabled()) {
throw new Error("Live view is disabled.");
}
// 创建实况窗
const defaultView = await LiveViewController.buildDefaultView();
return await liveViewManager.startLiveView(defaultView);
}
private static async buildDefaultView(): Promise<liveViewManager.LiveView> {
return {
// 构造实况窗请求体
id: 0, // 实况窗ID,开发者生成。
event: "QUEUE", // 实况窗的应用场景。QUEUE:排队
timer: {
time: 620000,
isCountdown: false,
isPaused: false
},
liveViewData: {
primary: {
title: "大桌4人等位 32桌",
content: [
{ text: "已等待 " },
{ text: "${placeholder.timer}", textColor:"#ff10c1f7" },
{ text: " | 预计还需>30分钟" }
], // 所有文本仅能设置为一种颜色,不设置textColor时,默认展示#FF000000
keepTime: 15,
clickAction: await LiveViewController.buildWantAgent(),
layoutData: {
layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_PROGRESS,
progress: 0,
color: "#FFFF0000",
backgroundColor: "#FF000000",
indicatorType: liveViewManager.IndicatorType.INDICATOR_TYPE_OVERLAY,
indicatorIcon: "indicator.png", // 进度条指示器图标,取值为
"/resources/rawfile"路径下的文件名
lineType: liveViewManager.LineType.LINE_TYPE_DOTTED_LINE,
nodeIcons: ["icon_1.png","icon_2.png"] // 进度条每个节点图标,取值为
"/resources/rawfile"路径下的文件名
}
}
}
};
}
... ...
}
3.本地更新和结束实况窗。
在本地创建完实况窗后,若应用业务状态发生变化,则需要调用liveViewManager的updateLiveView()更新实况窗,更新时对请求体中需要修改的对应参数进行修改。在该应用的服务进程结束时,需要调用stopLiveView()来结束实况窗。这里以即时配送场景的进度可视化模板为例,来说明更新和结束实况窗及实况胶囊的方法,具体示例代码如下:
import { liveViewManager } from '@kit.LiveViewKit';
import { Want, wantAgent } from '@kit.AbilityKit';
export class LiveViewController {
private static contentColor: string = '#FF000000';
private static capsuleColor: string = '#FF308977';
public async startLiveView(): Promise<liveViewManager.LiveViewResult> {
// 校验实况窗开关是否打开
if (!LiveViewController.isLiveViewEnabled()) {
throw new Error("Live view is disabled.");
}
// 创建实况窗
const defaultView = await LiveViewController.buildDefaultView();
return await liveViewManager.startLiveView(defaultView);
}
public async updateLiveView(): Promise<liveViewManager.LiveViewResult> {
// 校验实况窗开关是否打开
if (!LiveViewController.isLiveViewEnabled()) {
throw new Error("Live view is disabled.");
}
// 修改实况窗内容
const defaultView = await LiveViewController.buildDefaultView();
defaultView.liveViewData.primary.title = "预计23:49送达";
defaultView.liveViewData.primary.content = [
{ text: "等待商家接单,",
textColor: LiveViewController.contentColor },
{ text: "03:20未接单自动取消",
textColor: LiveViewController.contentColor }
];
defaultView.liveViewData.primary.layoutData = {
layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_PROGRESS,
progress: 0,
lineType: 0,
nodeIcons: [ // 进度条每个节点图标,取值为"/resources/rawfile"路径下的文件名
'icon_store_white.png',
'icon_finish.png'
]
};
defaultView.liveViewData.capsule = {
type: liveViewManager.CapsuleType.CAPSULE_TYPE_TEXT,
status: 1,
icon: 'capsule_store.png',
backgroundColor: LiveViewController.capsuleColor,
title: "待接单"
};
// 更新实况窗
return await liveViewManager.updateLiveView(defaultView);
}
public async stopLiveView(): Promise<liveViewManager.LiveViewResult> {
// 校验实况窗开关是否打开
if (!LiveViewController.isLiveViewEnabled()) {
throw new Error("Live view is disabled.");
}
// 修改实况窗内容
const defaultView = await LiveViewController.buildDefaultView();
defaultView.liveViewData.primary.title = '商品已送达';
defaultView.liveViewData.primary.content = [
{ text: '感谢您的认可,',
textColor: LiveViewController.contentColor },
{ text: '期待下一次光临',
textColor: LiveViewController.contentColor }
];
defaultView.liveViewData.primary.layoutData = {
layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_PROGRESS,
progress: 100,
lineType: 0,
nodeIcons: [ // 进度条每个节点图标,取值为"/resources/rawfile"路径下的文件名
'icon_order.png',
'icon_finish.png'
]
};
defaultView.liveViewData.capsule = {
type: liveViewManager.CapsuleType.CAPSULE_TYPE_TEXT,
status: 1,
icon: 'capsule_gps.png',
backgroundColor: LiveViewController.capsuleColor,
title: '已送达'
};
// 结束实况窗
return await liveViewManager.stopLiveView(defaultView);
}
private static async buildDefaultView(): Promise<liveViewManager.LiveView> {
return {
// 构造实况窗请求体
id: 0, // 实况窗ID,开发者生成。
event: "DELIVERY", // 实况窗的应用场景。DELIVERY:即时配送(外卖、生鲜)
liveViewData: {
primary: {
title: "餐品待支付",
content: [
{ text: "咖啡 ", textColor: "#FF000000" },
{ text: "等2件商品", textColor: "#FF000000" }
],
keepTime: 15,
clickAction: await LiveViewController.buildWantAgent(),
layoutData: {
layoutType: liveViewManager.LayoutType.LAYOUT_TYPE_PICKUP,
title: "待支付金额",
content: "25.5元",
underlineColor: "#FF0A59F7",
descPic: "coffee.png"
}
},
// 实况胶囊相关参数
capsule: {
type: liveViewManager.CapsuleType.CAPSULE_TYPE_TEXT,
status: 1,
icon: "capsule_store.png",
backgroundColor: "#FF308977",
title: "待支付",
content: "..."
}
}
};
}
... ...
}
了解更多详情>>
深度解析HarmonyOS SDK实况窗服务源码,Get不同场景下的多种模板的更多相关文章
- 深度解析Spring Cloud Ribbon的实现源码及原理
Ribbon的核心作用就是进行请求的负载均衡,它的基本原理如下图所示.就是客户端集成Ribbon这个组件,Ribbon中会针对已经配置的服务提供者地址列表进行负载均衡的计算,得到一个目标地址之后,再发 ...
- 【JVM】深度分析Java的ClassLoader机制(源码级别)
原文:深度分析Java的ClassLoader机制(源码级别) 为了更好的理解类的加载机制,我们来深入研究一下ClassLoader和他的loadClass()方法. 源码分析 public abst ...
- [WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析
[WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析 标签: webkit内核JavaScriptCore 2015-03-26 23:26 2285 ...
- java基础解析系列(十)---ArrayList和LinkedList源码及使用分析
java基础解析系列(十)---ArrayList和LinkedList源码及使用分析 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder jav ...
- 深度学习(七十一)darknet 源码阅读
深度学习(七十一)darknet 源码阅读
- JVM源码分析-类加载场景实例分析
A类调用B类的静态方法,除了加载B类,但是B类的一个未被调用的方法间接使用到的C类却也被加载了,这个有意思的场景来自一个提问:方法中使用的类型为何在未调用时尝试加载?. 场景如下: public cl ...
- QTimer源码分析(以Windows下实现为例)
QTimer源码分析(以Windows下实现为例) 分类: Qt2011-04-13 21:32 5026人阅读 评论(0) 收藏 举报 windowstimerqtoptimizationcallb ...
- 深度理解springboot集成cache缓存之源码解析
一.案例准备 1.创建数据表(employee表) 2.创建Employee实体类封装数据库中的数据 @AllArgsConstructor @NoArgsConstructor @Data @ToS ...
- http服务源码分析
多读go的源码,可以加深对go语言的理解和认知,今天分享一下http相关的源码部分 在不使用第三方库的情况下,我们可以很容易的的用go实现一个http服务, package main import ( ...
- 【源码解析】阿里在线诊断工具greys源码
撸起袖子加油干!开门见山! 一.源码下载 下载代码: git clone https://github.com/oldmanpushcart/greys-anatomy.git 二.源码分析 2.1 ...
随机推荐
- 从零开始学Spring Boot系列-集成Spring Security实现用户认证与授权
在Web应用程序中,安全性是一个至关重要的方面.Spring Security是Spring框架的一个子项目,用于提供安全访问控制的功能.通过集成Spring Security,我们可以轻松实现用户认 ...
- 解决python命令行报错问题
解决Python报错Failed calling sys.__interactivehook__ 报错截图 可以看到主要的报错信息 File "D:\Python\Anaconda3\lib ...
- Springboot整合Apollo
一.Apollo作用 随着程序功能的日益复杂,程序的配置日益增多:各种功能的开关.参数的配置.服务器的地址-- 对程序配置的期望值也越来越高:配置修改后实时生效,灰度发布,分环境.分集群管理配置,完善 ...
- c++临时对象导致的生命周期问题
对象的生命周期是c++中非常重要的概念,它直接决定了你的程序是否正确以及是否存在安全问题. 今天要说的临时变量导致的生命周期问题是非常常见的,很多时候没有一定经验甚至没法识别出来.光是我自己写.rev ...
- oeasy教您玩转vim - 69 - # 折叠folding入门
折叠入门 回忆上次 上次学习了一种新的容器 tabs选项卡 tabs选项卡 包含多个选项卡tab 可以列两个tab 一个编写文件 一个执行指令 互不影响 每个 tab选项卡 还可以对应多个wind ...
- 兼容sentry协议的轻量级监控,glitchtip
前言 上一篇文章说了重启 sentry 的事 因为过程太折腾了,一度想过放弃 sentry 换成其他比较轻量级的开源监控系统 这不就给我找到了另外俩个 https://glitchtip.com/ h ...
- 【VMware VCF】VMware Cloud Foundation Part 03:准备 Excel 参数表。
VMware Cloud Foundation 使用 VMware Cloud Builder 工具完成自动化以及标准化的部署,除了要准备必须的用于部署管理域并运行管理相关组件的 ESXi 主机以外, ...
- useRoute 函数的详细介绍与使用示例
title: useRoute 函数的详细介绍与使用示例 date: 2024/7/27 updated: 2024/7/27 author: cmdragon excerpt: 摘要:本文介绍了Nu ...
- python 私有属性的作用
python 私有属性的作用 class Player(): def __init__(self, name, power, skill): self.name = name self.power = ...
- ThinkPHP6支持金仓数据库(Kingbase)解决无法使用模型查询问题
参考了很多前人的文章,最后只支持Db::query原生查询,不支持thinkphp数据模型方法,这在实际项目中是很难接受的,特分享出解决方案. 先按照流程配置如下: 1.准备工作 首先确认PHP支持金 ...