WPF项目学习.四
信息收录项目
版权声明:本文为博主初学经验,未经博主允许不得转载。
一、前言
记录在学习与制作WPF过程中遇到的解决方案。
需求文案、设计思路、简要数据库结构、简要流程图和明细代码,动图细化每步操作,入门级引导文章;
项目功能包括:登录、首页、数据维护 和 全文搜索等增删查改的常用操作;
二、配置
系统环境:
win10
开发工具:
Visual Studio 2017
开发语言:
C#.WPF (MVVM框架)
数据库:
SQLiteStudio
三、附件
- vs_enterprise.exe 在线安装 Visual Studio 2017 开发工具;
- SQLiteStudio.zip 免安装Sqlite轻量数据库操作工具;
- SearchData.zip 项目源代码;
四、项目需求
1. 项目背景:
前一段时间,一个老同事找到我说,有个项目一起搞,他负责营销,我负责平台;然后我就咨询了他关于项目的理念,听完通过电话聊天的述讲后,我只能呵呵一句,因为他还是着眼于眼前的需求,为了不打击他的激情,我不评论项目发展前景;完全配合他的计划,并加以我的思想完善整个项目趋势;接着就约了个时间详谈;通过茶水间的讨论后,才知道他只是要一个专属的OA平台而已,需求也甚是简单;因此我直接用该需求来作为项目制作的全过程指导文章;
2. 项目概述:
文字描述:
做一个信息搜索平台,平台主要角色是需求方信息,用户信息和解决需求的信息;
举例描述:我拿到一个厂家销售共享冰箱的项目,通过平台快速搜索到相关代理商和有共享方面销售的企业;
或者厂家直接通过平台搜索有能力解决他商品销售的企业,然后通过平台联系,平台赚取中介费;
流程图描述:
3. 需求目标:
把需求的数据有效统一整理,方便查阅,快速处理需求方和解决方的对接;
持久化有质量且高效的对接案例,从而能够为后续发展做铺垫;
4. 用户介绍
注册用户,游客,管理员;
用户类型包括厂家,小作坊,企业,商家,个人,代理商等等各种行业;
5. 功能
登录功能,搜索功能,数据维护的新增和编辑,数据的导出和导入,注册用户不能查阅其他用户维护的数据;
6. 项目制作时间规划
.(个人单独开发).
7. 风险评估
由于经济条件,目前先制作离线本地版本,后期改进后再数据统一管理;
五、设计思路
使用MVVM的其中一个优点在于数据与视图的设计分离;
因此可以省略画草图,直接进行视图设计;
1. 登录页面
登录输入包括账号和密码,密码用“*”号隐藏字符;输入框带有水印提示;
2. 注册页面
注册输入包括账号,密码,手机号,邮箱,QQ等信息进行收录。同时,登录的时候也可以用账号、手机号、邮箱和QQ;
由于注册页面的输入框做了一个自定义控件,所以在前端设计时并没有赋值,待完善后台代码,项目运行启动时自动赋值;
3. 数据维护页面
维护数据包括公司名称,联系姓名,电话,邮箱,QQ,法人代表,法人联系方式,企业固话,传真,营业执照,税号,注册资本,等级资质,地址,销售物品相关,企业标签,公司简介,备注;
百度了一下公司的组成信息就写了这些,备注算是补充字段了,后期再搞一个版本是自定义维护字段,这一期先不弄;
4. 导出页面
根据时间,标签和销售相关进行数据导出;
5. 搜索页面
模糊搜索,可以搜索所有字段信息;
可以自定义列的显示,左边是搜索结果,右边是点击左边搜索结果的条目后,阅览更详细的信息;
但更详细的信息中却隐藏了关键信息,拥有相关权限的用户点击联系客服后会显示关键信息,其他普通权限的用户只会以邮件的详细发给设置好的客服索取关键信息;
6. 设置页面
关键信息设置隐藏,基础邮箱配置;
7. 样式使用的操作动图
六、数据库结构
1. 引用:
Chloe.dll ; Chloe.SQLite ; System.Data.SQLite
2. SQLite的数据库常规操作的通用类
public class SqLiteSqlHelper
{
private readonly string _connectionString;
public SqLiteSqlHelper()
{
_connectionString = DbConfiger.SqLiteConnectionString;
} /// <summary>
/// 构造函数
/// </summary>
/// <param name="dbPath">SQLite数据库文件路径</param>
public SqLiteSqlHelper(string dbPath)
{
_connectionString = "Data Source=" + dbPath;
} /// <summary>
/// 对SQLite数据库执行增删改操作,返回受影响的行数。
/// </summary>
/// <param name="sql">要执行的增删改的SQL语句</param>
/// parameters 执行增删改语句所需要的参数,参数必须以它们在SQL语句中的顺序为准
public int ExecuteNonQuery(string sql, SQLiteParameter[] parameters)
{
int affectedRows;
using (var connection = new SQLiteConnection(_connectionString))
{
connection.Open();
using (DbTransaction transaction = connection.BeginTransaction())
{
using (var command = new SQLiteCommand(connection))
{
command.CommandText = sql;
if (parameters != null)
command.Parameters.AddRange(parameters);
affectedRows = command.ExecuteNonQuery();
}
transaction.Commit();
}
}
return affectedRows;
} /// <summary>
/// 执行一个查询语句,返回一个关联的SQLiteDataReader实例
/// </summary>
/// <param name="sql">要执行的查询语句</param>
/// parameters 执行SQL查询语句所需要的参数,参数必须以它们在SQL语句中的顺序为准
public SQLiteDataReader ExecuteReader(string sql,SQLiteParameter[] parameters)
{
var connection = new SQLiteConnection(_connectionString);
var command = new SQLiteCommand(sql, connection);
if (parameters != null)
{
command.Parameters.AddRange(parameters);
}
connection.Open();
return command.ExecuteReader(CommandBehavior.CloseConnection);
} /// <summary>
/// 执行一个查询语句,返回一个包含查询结果的DataTable
/// </summary>
public DataTable ExecuteDataTable(string sql, SQLiteParameter[] parameters)
{
using (var connection = new SQLiteConnection(_connectionString))
{
using (var command = new SQLiteCommand(sql, connection))
{
if (parameters != null)
command.Parameters.AddRange(parameters);
var adapter = new SQLiteDataAdapter(command);
var data = new DataTable();
adapter.Fill(data);
return data;
}
}
} /// <summary>
/// 执行一个查询语句,返回查询结果的第一行第一列
/// </summary>
public object ExecuteScalar(string sql, SQLiteParameter[] parameters)
{
object obj;
using (var connection = new SQLiteConnection(_connectionString))
{
using (var command = new SQLiteCommand(sql, connection))
{
if (parameters != null)
command.Parameters.AddRange(parameters);
connection.Open();
obj = command.ExecuteScalar();
connection.Close();
}
}
return obj;
} /// <summary>
/// 查询数据库中的所有数据类型信息
/// </summary>
public DataTable GetSchema()
{
using (var connection = new SQLiteConnection(_connectionString))
{
connection.Open();
var data = connection.GetSchema("TABLES");
connection.Close();
return data;
}
}
}
判断表是否存在
public static bool IsExistsTable(string tableName)
{
var sql = string.Format(@"
SELECT COUNT(*)
FROM sqlite_master
where type='table' and name='{0}';",
tableName);
var count = new SqLiteSqlHelper().ExecuteScalar(sql, null);
return Convert.ToInt16(count) > ;
}
数据库数据用实体类操作
/// <summary>
/// SQLite数据访问
/// </summary>
private static readonly SqLiteDbProvider DbProvider = new SqLiteDbProvider(); /// <summary>
/// 获取用户数据
/// </summary>
public static List<Users> GetUsers(string id)
{
var result = DbProvider.DbContext.Query<Users>()
.Where(t => t.Id == id).ToList();
if (result != null) return result;
result = DbProvider.DbContext.Query<Users>()
.Where(t => t.UserCode == id
|| t.Phone == id
|| t.Email == id
|| t.Qq == id).ToList();
return result;
}
/// 更新用户数据
public static void Delete(Contents content)
{
if (content == null) return;
DbProvider.DbContext.Update<Contents>(t => t.Id == content.Id, t => content);
}
3. 数据库表
3.1 用户信息表
3.2 企业信息表
3.3 系统配置表
4. 库表关系
5.配套实体类写在Model层
这里就不贴代码了,具体看源代码;
七、通用代码集
【GuidHelper】
/// 获取有序的唯一ID。
public static Guid GenerateComb(
SequentialGuidType sequentialGuidType = SequentialGuidType.SequentialAsString)
{
return SequentialGuidGenerator.NewSequentialGuid(sequentialGuidType);
}
// 根据枚举生成不同的有序GUID
private static class SequentialGuidGenerator
{
private static readonly RNGCryptoServiceProvider Rng = new RNGCryptoServiceProvider();
public static Guid NewSequentialGuid(SequentialGuidType guidType)
{
var randomBytes = new byte[];
Rng.GetBytes(randomBytes);
var timestamp = DateTime.UtcNow.Ticks / 10000L;
var timestampBytes = BitConverter.GetBytes(timestamp);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(timestampBytes);
}
var guidBytes = new byte[];
switch (guidType)
{
case SequentialGuidType.SequentialAsString:
case SequentialGuidType.SequentialAsBinary:
Buffer.BlockCopy(timestampBytes, , guidBytes, , );
Buffer.BlockCopy(randomBytes, , guidBytes, , );
if (guidType == SequentialGuidType.SequentialAsString
&& BitConverter.IsLittleEndian)
{
Array.Reverse(guidBytes, , );
Array.Reverse(guidBytes, , );
}
break;
case SequentialGuidType.SequentialAtEnd:
Buffer.BlockCopy(randomBytes, , guidBytes, , );
Buffer.BlockCopy(timestampBytes, , guidBytes, , );
break;
}
return new Guid(guidBytes);
}
}
/// <summary>
/// 有序GUID的类型
/// sqlServer用AtEnd;
/// mysql用AsString或者AsBinary;
/// oracle用AsBinary;
/// postgresql用AsString或者AsBinary;
/// </summary>
public enum SequentialGuidType
{
SequentialAsString,
SequentialAsBinary,
SequentialAtEnd
}
【JsonHelper】
/// <summary>
/// 转换成JSON格式
/// </summary>
/// <typeparam name="T">转换类型</typeparam>
/// <param name="obj">string内容</param>
public static T ToJson<T>(this string obj) where T : class, new()
{
var model = new T();
var serializer = new DataContractJsonSerializer(model.GetType());
var mStream = new MemoryStream(Encoding.UTF8.GetBytes(obj));
return serializer.ReadObject(mStream) as T;
} /// <summary>
/// JSON转换String
/// </summary>
/// <typeparam name="T">转换类型</typeparam>
/// <param name="obj">Json内容</param>
public static string JsonToString<T>(this T obj)
{
var serializer = new DataContractJsonSerializer(obj.GetType());
var mStream = new MemoryStream();
serializer.WriteObject(mStream, obj);
byte[] dataBytes = new byte[mStream.Length];
mStream.Position = ;
mStream.Read(dataBytes, , (int) mStream.Length);
return Encoding.UTF8.GetString(dataBytes);
}
【LoggerHelper】
/// <summary>
/// 插入日志内容
/// </summary>
/// <param name="msg">内容</param>
public static void Insert(string msg)
{
Insert(msg, "Logger");
}
/// <summary>
/// 插入日志内容
/// </summary>
/// <param name="msg">内容</param>
/// <param name="logName">日志名称</param>
public static void Insert(string msg, string logName)
{
var name=Path.Combine(AppDomain.CurrentDomain.BaseDirectory,logName+".dat");
using (var sw = new StreamWriter(name, true, Encoding.UTF8))
{
sw.WriteLineAsync($"{DateTime.Now} {msg}");
}
}
【TryCatch】
/// <summary>
/// 切换回主UI线程 并加Try Catch处理事件
/// </summary>
/// <param name="action">try里面的执行方法</param>
/// <param name="param">try里面的方法参数</param>
/// <param name="msg">系统异常</param>
/// <param name="workMsg">正常业务异常</param>
/// <param name="end">finally执行的事件</param>
public static void TryInvoke<T>(Action<T> action, T param,
string msg = null, string workMsg = null, Action end = null)
{
try
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
action(param);
}));
}
catch (Common.BaseModels.WorkException e)
{
var errWord = workMsg ?? "业务异常";
var err = $"{errWord}:{e.Message}";
MessageBoxManager.ShowWorkError(err);
}
catch (Exception ex)
{
var errWord = msg ?? "系统异常";
var err = $"{errWord}:{ex.Message}";
Common.LoggerHelper.Insert(ex);
MessageBoxManager.ShowError(err);
}
finally
{
end?.Invoke();
}
}
【TabControlManager】(标签管理)
/// <summary>
/// 添加标签页子项
/// </summary>
public static void AddTabItem(TabControl tabControl, TabItem tabItem)
{
if (!IsContains(tabControl, tabItem, out var selectedIndex))
tabControl.Items.Add(tabItem);
tabControl.SelectedIndex = selectedIndex;
}
/// <summary>
/// 检查tabItem是否已经包含在了tabControl中
/// </summary>
public static bool IsContains(
TabControl tabControl, TabItem tabItem, out int selectedIndex)
{
selectedIndex = ;
foreach (TabItem item in tabControl.Items)
{
if (item.Name == tabItem.Name)
return true;
selectedIndex++;
}
return false;
}
【ConvertHelper】
/// <summary>
/// 将原数据转为目标数据
/// 注:支持批量,但只支持列表接口子类,如:List
/// </summary>
public static TTo ConvertToTResult<TFrom, TTo>(
TFrom t, DefaultMapConfig defaultMapConfig = null)
{
var mapper = ObjectMapperManager.DefaultInstance.GetMapper<TFrom, TTo>(
defaultMapConfig ?? new DefaultMapConfig());
return mapper.Map(t);
} public static TTo ConvertTo<TFrom, TTo>(
this TFrom t, DefaultMapConfig defaultMapConfig = null)
{
var mapper = ObjectMapperManager.DefaultInstance.GetMapper<TFrom, TTo>(
defaultMapConfig ?? new DefaultMapConfig());
return mapper.Map(t);
} public static T Convert<T>(DataTable tb) where T : class
{
var lst = DataTableToEntity<T>(tb);
return lst.Any() ? lst.FirstOrDefault() : default(T);
} public static List<T> ConvertEnumToList<T>() where T : struct
{
return Enum.GetValues(typeof(T)).Cast<T>().ToList();
} /// <summary>
/// 将datatable转为实体
/// </summary>
public static IList<T> DataTableToEntity<T>(DataTable tb) where T : class
{
if (!HasRows(tb))
return new List<T>();
var lst = new List<T>();
foreach (DataRow item in tb.Rows)
{
var t = Activator.CreateInstance<T>();
foreach (DataColumn col in tb.Columns)
{
//先判断属性
var pi = t.GetType().GetProperty(col.ColumnName,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
//再判断列
var objValue = item[col.ColumnName];
if (pi != null
&& pi.PropertyType == col.DataType
&& pi.CanWrite && (objValue != null
&& objValue != DBNull.Value))
{
pi.SetValue(t, objValue, null);
}
}
lst.Add(t);
}
return lst;
} /// <summary>
/// 将列头含有特殊字符的datatable转为实体
/// </summary>
/// <typeparam name="T">目标类型</typeparam>
/// <param name="tb">原数据table</param>
public static IList<T> DataTableToEntityWithColumnChar<T>(DataTable tb) where T : class
{
if (!HasRows(tb))
return new List<T>();
var lst = new List<T>();
foreach (DataRow item in tb.Rows)
{
var t = Activator.CreateInstance<T>();
foreach (DataColumn col in tb.Columns)
{
var tbColumnName = col.ColumnName;
var entityPropertyName = ReplaceSpecialChar(tbColumnName);
//先判断属性
var pi = t.GetType().GetProperty(entityPropertyName,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
//再判断列
var objValue = item[tbColumnName];
if (pi != null
&& pi.PropertyType == col.DataType
&& pi.CanWrite && (objValue != null
&& objValue != DBNull.Value))
{
pi.SetValue(t, objValue, null);
}
}
lst.Add(t);
}
return lst;
}
【CloseableTabItem】
public delegate void CloseButtonDelegate(object sender, RoutedEventArgs e);
/// <summary>
/// 选项卡TabItem关闭时事件
/// </summary>
public event RoutedEventHandler TabItemClosing;
/// <summary>
/// 实例化标签项
/// </summary>
public CloseableTabItem(): this("New tab"){}
/// <summary>
/// 实例化标签项(给定标题)
/// </summary>
/// <param name="title">新标签项的标题字符串</param>
public CloseableTabItem(string title)
: this(title, SortWay.NotSort){} /// <summary>
/// 实例化标签项(给定标题,给定是否自动排序)
/// </summary>
/// <param name="title">标题</param>
/// <param name="sortWay"></param>
public CloseableTabItem(string title, SortWay sortWay)
{
//设定样式
Style = (Style) Application.Current.Resources["TabItemStyle"];
//生产一个可关闭的Header
var ctih = CreateCloseableTabItem();
//自动排序
switch (sortWay)
{
case SortWay.IsAutoSort:
break;
case SortWay.NotSort:
break;
}
//设定标题
ctih.Title = title;
//设定名称
Name = title;
//设定Header
Header = ctih;
} /// <summary>
/// 创建一个标签页头
/// </summary>
/// <returns>标签页头(自定义控件)</returns>
private PageTabItemHeader CreateCloseableTabItem()
{
//实例化一个Header
var ctih = new PageTabItemHeader();
//添加关闭按钮点击事件
ctih.BtnClose.Click += btnClose_Click;
//返回Header
return ctih;
} /// <summary>
/// 关闭按钮的点击事件处理方法
/// </summary>
private void btnClose_Click(object sender, RoutedEventArgs e)
{
// 触发标签项关闭事件
TabItemClosing?.Invoke(sender, e);
if (!e.Handled)
{
//关闭当前TabItem
GetParentObject<TabControl>(this).Items.Remove(this);
}
} /// <summary>
/// 获得指定元素的父元素
/// </summary>
/// <typeparam name="T">父级元素类型</typeparam>
/// <param name="obj">指定查找元素</param>
public T GetParentObject<T>(DependencyObject obj) where T : FrameworkElement
{
//返回可视对象的父对象
DependencyObject parent = VisualTreeHelper.GetParent(obj);
//按层、类型提取父级
while (parent != null)
{
if (parent is T)
return (T) parent;
parent = VisualTreeHelper.GetParent(parent);
}
//返回
return null;
}
Tab标签页制作跳转
前端:
<TabControl Name="TabControlGrid" TabStripPlacement="Top"
Width="{Binding ElementName=Grid,Path=ActualWidth}"
Height="{Binding ElementName=Grid,Path=ActualHeight}" >
<TabItem Header="Search">
<Frame Source="Content/Search.xaml" NavigationUIVisibility="Hidden">
<Frame.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="DarkSeaGreen" Offset=""/>
<GradientStop Color="White" Offset=""/>
</LinearGradientBrush>
</Frame.Background>
</Frame>
</TabItem>
</TabControl> 后端:
/// <summary>
/// 添加用户控件
/// </summary>
private CloseableTabItem AddUserControl(IFrameworkInputElement uc)
{
var ti = new CloseableTabItem(uc.Name) { Content = uc };
TabControlManager.AddTabItem(TabControlGrid, ti);
return ti;
}
/// <summary>
/// 添加Page页
/// </summary>
private void AddPage(IFrameworkInputElement uc)
{
var ti = new CloseableTabItem(uc.Name)
{Content = new Frame {Content = uc}};
TabControlManager.AddTabItem(TabControlGrid, ti);
}
private void EditClick(object sender, RoutedEventArgs e)
{
AddPage(new Content.Edit());
}
八、项目手册
贴图较多,查阅PPT;
九、下篇预告;
MVC制作站点过程;
WPF项目学习.四的更多相关文章
- Spring Boot 项目学习 (四) Spring Boot整合Swagger2自动生成API文档
0 引言 在做服务端开发的时候,难免会涉及到API 接口文档的编写,可以经历过手写API 文档的过程,就会发现,一个自动生成API文档可以提高多少的效率. 以下列举几个手写API 文档的痛点: 文档需 ...
- WPF项目学习.一
WPF项目搭建 版权声明:本文为博主初学经验,未经博主允许不得转载. 一.前言 记录在学习与制作WPF过程中遇到的解决方案. 使用MVVM的优点是 数据和视图分离,双向绑定,低耦合,可重用行,相对独立 ...
- WPF项目学习.二
WPF用MVVM的解决记录 版权声明:本文为博主初学经验,未经博主允许不得转载. 一.前言 记录在学习与制作WPF过程中遇到的解决方案. 焦点的控制,键盘事件触发,输入框的数字限制,异步处理,隐藏状 ...
- WPF项目学习.三
工具代码记录 版权声明:本文为博主初学经验,未经博主允许不得转载. 一.前言 记录在学习与制作WPF过程中遇到的解决方案. 分页控件的制作,邮件发送,日志代码,excel导入导出等代码的实现过程: 二 ...
- WPF Binding学习(四) 绑定各种数据源
转自:http://blog.csdn.net/lisenyang/article/details/18312199 1.集合作为数据源 首先我们先创建一个模型类 public class Stude ...
- Spring Boot 项目学习 (三) Spring Boot + Redis 搭建
0 引言 本文主要介绍 Spring Boot 中 Redis 的配置和基本使用. 1 配置 Redis 1. 修改pom.xml,添加Redis依赖 <!-- Spring Boot Redi ...
- Spring Boot 项目学习 (一) 项目搭建
0 引言 本文主要记录借用Idea 开发环境下,搭建 Spring Boot 项目框架的过程. 1 系列文档目录 Spring Boot 项目学习 (一) 项目搭建 Spring Boot 项目学习 ...
- Spring Boot 项目学习 (二) MySql + MyBatis 注解 + 分页控件 配置
0 引言 本文主要在Spring Boot 基础项目的基础上,添加 Mysql .MyBatis(注解方式)与 分页控件 的配置,用于协助完成数据库操作. 1 创建数据表 这个过程就暂时省略了. 2 ...
- 年度巨献-WPF项目开发过程中WPF小知识点汇总(原创+摘抄)
WPF中Style的使用 Styel在英文中解释为”样式“,在Web开发中,css为层叠样式表,自从.net3.0推出WPF以来,WPF也有样式一说,通过设置样式,使其WPF控件外观更加美化同时减少了 ...
随机推荐
- C#将.spl剥离成.emf文件格式
本文转载自 星战紫辉 http://www.cppblog.com/rawdata/archive/2009/02/23/74653.html 但C#代码实现为本人原创.https://github. ...
- Linux环境下安装配置Node.js
1.在官网查看版本,LTS代表长期支持的版本 2.进入服务器 3.输入命令:·wget https://npm.taobao.org/mirrors/node/v8.9.3/node-v8.9.3-l ...
- IPFS开发团队是如何工作的?
小编不是一个很八卦的人,连当红明星都认不全.不过,今天还是带领大家来扒一扒ipfs开发团队是如何工作的. 工作方式: 全体会议:每周一有一个全体会议,这个会议是提前安排好的一个日程 任务讨论:把大任务 ...
- 前端的UI设计与交互之设计原则篇
1.亲密性 a)纵向间距示例这三种规格分别为:8px(小号间距).16px(中号间距).24px(大号间距). b)在这三种规格不适用的情况下,可以通过加减『基础间距』的倍数,或者增加元素来拉开信息层 ...
- Vue:渲染、指令、事件、组件、Props、Slots
如果要我用一句话描述使用 Vue 的经历,我可能会说“它如此合乎常理”或者“它提供给我需要的工具,而且没有妨碍我的工作”.每当学习 Vue 的时候,我都很高兴,因为很有意义,而且很优雅. 以上是我对 ...
- MSIL实用指南-生成索引器
MSIL实用指南-生成索引器 索引器是一种特殊的属性,它有参数的,也有get和set方法,属性名称一般是"Item",并且方法名称一般名称是"get_Item" ...
- WebPack介绍
一.Webpack 是什么 Webpack 是德国开发者 Tobias Koppers 开发的模块加载器,Instagram 工程师认为这个方案很棒, 似乎还把作者招过去了.在 Webpack 当中, ...
- nuxt 运行项目后 中总是报错
报错的内容: nuxt.config.js中的图片 如果出现第一张图的中的错误: 请注释掉第二张图中extend里面的loader:'eslit-loader',或者把extend里面if下面的内容全 ...
- (转)SQLite内置函数
一.聚合函数: SQLite中支持的聚合函数在很多其他的关系型数据库中也同样支持,因此我们这里将只是给出每个聚集函数的简要说明,而不在给出更多的示例了.这里还需要进一步说明的是,对于所有聚合函数而言, ...
- (译文)学习ES6非常棒的特性——Async / Await函数
try/catch 在使用Async/Await前,我们可能这样写: const main = (paramsA, paramsB, paramsC, done) => { funcA(para ...