C#NPOI.RabbitMQ.EF.Attribute.HttpRuntime.Cache.AD域.List根据指定字段去重.前端JQuery.Cache.I18N(多语言).data-xx(自定义属性)
使用npoi 操作excel
个人使用的电脑基本默认安装excel 操作起来
调用excel的组件便可.如果是一台服务器.没有安装excel,也就无法调用excel组件.
在此推荐第三方插件.npoi 支持xls(2007)和xlsx(2012)读写.
using npoi.hssf.usermodel; using npoi.ss.usermodel; using npoi.xssf.usermodel; using system; using system.collections.generic; using system.configuration; using system.data; using system.io; namespace webapplication1.helper { public class excelhelper : idisposable { private string filename = null; //文件名 private iworkbook workbook = null; private filestream fs = null; private bool disposed; public excelhelper(string filename) { this.filename = filename; disposed = false; fs = new filestream(filename, filemode.open, fileaccess.read); if (filename.indexof(".xlsx") > 0) // 2007版本 workbook = new xssfworkbook(fs); else if (filename.indexof(".xls") > 0) // 2003版本 workbook = new hssfworkbook(fs); } public list<string> sheetname { get { list<string> data = null; if (workbook != null) { data = new list<string>(); for (int i = 0; i < workbook.numberofsheets; i++) { data.add(workbook.getsheetat(i).sheetname.tostring()); } } return data; } } public int sheetcount { get { return workbook == null ? 0 : workbook.numberofsheets; } } /// <summary> /// 将excel中的数据导入到datatable中 /// </summary> /// <param name="sheetname">excel工作薄sheet的名称</param> /// <param name="isfirstrowcolumn">第一行是否是datatable的列名</param> /// <returns>返回的datatable</returns> public datatable exceltodatatable(string sheetname, bool isfirstrowcolumn) { isheet sheet = null; datatable data = new datatable(); int startrow = 0; try { //fs = new filestream(filename, filemode.open, fileaccess.read); //if (filename.indexof(".xlsx") > 0) // 2007版本 // workbook = new xssfworkbook(fs); //else if (filename.indexof(".xls") > 0) // 2003版本 // workbook = new hssfworkbook(fs); if (sheetname != null) { sheet = workbook.getsheet(sheetname); if (sheet == null) //如果没有找到指定的sheetname对应的sheet,则尝试获取第一个sheet { sheet = workbook.getsheetat(0); } } else { sheet = workbook.getsheetat(0); } if (sheet != null) { irow firstrow = sheet.getrow(0); int cellcount = firstrow.lastcellnum; //一行最后一个cell的编号 即总的列数 if (isfirstrowcolumn) { for (int i = firstrow.firstcellnum; i < cellcount; ++i) { icell cell = firstrow.getcell(i); if (cell != null) { string cellvalue = cell.stringcellvalue; if (cellvalue != null) { datacolumn column = new datacolumn(cellvalue); data.columns.add(column); } } } startrow = sheet.firstrownum + 1; } else { startrow = sheet.firstrownum; } //最后一列的标号 int rowcount = sheet.lastrownum; for (int i = startrow; i <= rowcount; ++i) { irow row = sheet.getrow(i); if (row == null) continue; //没有数据的行默认是null datarow datarow = data.newrow(); for (int j = row.firstcellnum; j < cellcount; ++j) { if (row.getcell(j) != null) //同理,没有数据的单元格都默认是null datarow[j] = row.getcell(j).tostring(); } data.rows.add(datarow); } } return data; } catch (exception ex) { console.writeline("exception: " + ex.message); return null; } } public static void createexcel(string projectname) { try { string filename = $"{projectname}.xlsx"; // 文件名称 string filepath = $"{configurationmanager.appsettings["file"].tostring()}" + "\\" + filename; // 2.解析单元格头部,设置单元头的中文名称 xssfworkbook workbook = new xssfworkbook(); // 工作簿 isheet sheet = workbook.createsheet("sheet"); //#region 设置excel表格第一行的样式 //irow titleinfo = sheet.createrow(0); //icell celltitle = titleinfo.createcell(0); //celltitle.setcellvalue("会员信息批量录入模板"); //icellstyle titlestyle = workbook.createcellstyle(); //ifont titlefont = workbook.createfont(); //titlefont.fontheightinpoints = 25; //titlefont.boldweight = short.maxvalue;//字体加粗 //titlestyle.setfont(titlefont); //celltitle.cellstyle = titlestyle; //#endregion //irow datafields = sheet.createrow(2); //icellstyle style = workbook.createcellstyle();//创建样式对象 //style.alignment = horizontalalignment.center;//水平对齐 //style.verticalalignment = verticalalignment.center;//垂直对齐 //ifont font = workbook.createfont(); //创建一个字体样式对象 //font.fontname = "宋体"; //和excel里面的字体对应 //font.color = new hssfcolor.red().getindex();//颜色参考npoi的颜色对照表(替换掉pink()) //font.fontheightinpoints = 10;//字体大小 //font.boldweight = short.maxvalue;//字体加粗 //style.setfont(font); //将字体样式赋给样式对象 //sheet.setcolumnwidth(0, 20 * 256);//设置列宽 //string[] colums = { "*会员卡号", "*会员手机", "*会员姓名", "*会员等级", "会员性别", "电子邮箱", "会员状态", "固定电话", "永久有效", "身份证号", "开卡费用", "会员地址", "备注信息" }; //icell cell = null; //for (int i = 0; i < colums.count(); i++) //{ // cell = datafields.createcell(i); // cell.cellstyle = style; // cell.setcellvalue(colums[i]); // sheet.setcolumnwidth(i, 17 * 256); //} //sheet.addmergedregion(new cellrangeaddress(0, 0, 0, colums.count()));//合并单元格 // 4.生成文件 filestream file = new filestream(filepath, filemode.create); workbook.write(file); file.close(); } catch (exception ex) { throw ex; } } public void dispose() { dispose(true); gc.suppressfinalize(this); } protected virtual void dispose(bool disposing) { if (!this.disposed) { if (disposing) { if (fs != null) fs.close(); } fs = null; disposed = true; } } } }
读:
using (excelhelper excelhelper = new excelhelper(configurationmanager.appsettings["excelfile"])) { var datatable = excelhelper.exceltodatatable(null, true); }
configurationmanager.appsettings["excelfile"]) 指文件位置 exceltodatatable(null, true); sheetname指excel中每个sheet的名字 isfirstrowcolumn指第一行是否是列名
写:
excelhelper.createexcel(projectname); filestream fs = new filestream($"{configurationmanager.appsettings["file"].tostring()}\\{projectname}.xlsx", filemode.open, fileaccess.read); iworkbook workbook = new xssfworkbook(fs); for (int i = 0; i < sheet.count; i++) { var srarch = data.where(a => a.sheet == sheet[i]).tolist(); datatable datatable = new datatable(); datatable.columns.add("template"); datatable.columns.add("code"); datatable.columns.add("zh_cn"); datatable.columns.add("description"); datatable.columns.add("en_us"); datatable.columns.add("zh_tw"); datatable.columns.add("ko"); datatable.columns.add("zh_hk"); for (int a = 0; a < srarch.count; a++) { datarow row = datatable.newrow(); row[0] = srarch[a].template; row[1] = srarch[a].code; row[2] = srarch[a].zh_cn; row[3] = srarch[a].description; row[4] = srarch[a].en_us; row[5] = srarch[a].zh_tw; row[6] = srarch[a].ko; row[7] = srarch[a].zh_hk; datatable.rows.add(row); } datatable.tablename = sheet[i]; isheet sheet = workbook.createsheet(datatable.tablename); //表头 irow row2 = sheet.createrow(0); for (int a = 0; a < datatable.columns.count; a++) { icell cell = row2.createcell(a); cell.setcellvalue(datatable.columns[a].columnname); } //数据 for (int a = 0; a < datatable.rows.count; a++) { irow row1 = sheet.createrow(a + 1); for (int j = 0; j < datatable.columns.count; j++) { icell cell = row1.createcell(j); cell.setcellvalue(datatable.rows[a][j].tostring()); } } } memorystream stream = new memorystream(); workbook.write(stream); var buf = stream.toarray(); //保存为excel文件 using (filestream fs1 = new filestream($"{configurationmanager.appsettings["file"].tostring()}\\{projectname}.xlsx", filemode.open, fileaccess.write)) { fs1.write(buf, 0, buf.length); fs1.flush(); }
excelhelper.createexcel(projectname);
创建excel ,projectname 是excel名字,路径默认是解决方案下file文件夹
两个for循环,第一个循环是创建列名,第二个循环是创建列下字段的内容
当然这只是创建datatable
所以后面还有两个循环 将每个table中列名放到excel中的sheet.以及内容
最后fs1.write写入excel
rabbitmq
是一种应用程序对应用程序的通信方法
举个例子
前端站点向服务站点发起请求。一般服务站点要考虑到并发和数据总量保持运行稳定.
如果前端的请求发送到rabbit并做持久化.服务端隔段时间批量响应请求。就大大减少了服务站点的压力
接下来的栗子就是a站点向rabbit发消息并走入队列.然后b站点拉取消息并回应,至于隔多久取,一次取多少条.这部分就没做限制(计数就好).
下面是a站点
connectionfactory factory = new connectionfactory(); factory.hostname = "127.0.0.1"; //默认端口 factory.port = 5672; factory.username = "guest";//用户名 factory.password = "guest";//密码 using (iconnection conn = factory.createconnection()) { using (imodel channel = conn.createmodel()) { //在mq上定义一个持久化队列,如果名称相同不会重复创建 channel.queuedeclare("mqtest", true, false, false, null); while (true) { string message = string.format("message_{0}", console.readline()); byte[] buffer = encoding.utf8.getbytes(message); ibasicproperties properties = channel.createbasicproperties(); properties.deliverymode = 2; channel.basicpublish("", "mqtest", properties, buffer); console.writeline("消息发送成功:" + message); } } }
消息在rabbit中.a接触rabbit,b接触rabbit.
最终是ab交互.但是过程相互不接触
connectionfactory factory = new connectionfactory(); factory.hostname = "127.0.0.1"; //默认端口 factory.port = 5672; factory.username = "guest";//用户名 factory.password = "guest";//密码 using (iconnection conn = factory.createconnection()) { using (imodel channel = conn.createmodel()) { //在mq上定义一个持久化队列,如果名称相同不会重复创建 channel.queuedeclare("mqtest", true, false, false, null); //输入1,那如果接收一个消息,但是没有应答,则客户端不会收到下一个消息 channel.basicqos(0, 1, false); console.writeline("listening..."); //在队列上定义一个消费者 queueingbasicconsumer consumer = new queueingbasicconsumer(channel); //消费队列,并设置应答模式为程序主动应答 channel.basicconsume("mqtest", false, consumer); while (true) { //阻塞函数,获取队列中的消息 basicdelivereventargs ea = (basicdelivereventargs)consumer.queue.dequeue(); byte[] bytes = ea.body; string str = encoding.utf8.getstring(bytes); console.writeline("队列消息:" + str.tostring()); //回复确认 channel.basicack(ea.deliverytag, false); } } }
ef
像这个被大家用的滚瓜烂熟的框架.我这会拿出来说似乎有点小儿科.不过我就是要写(还写得贼简单)
nuget中引入ef
自定义dbcontext继承dbcontext
public class hoteldbcontext : dbcontext { public hoteldbcontext() : base("name=conncodefirst") { database.setinitializer(new migratedatabasetolatestversion<hoteldbcontext, configuration>("conncodefirst")); } public dbset<tsm_admin1111111111111> tsm_admin { get; set; } }
conncodefirst 是数据库连接字符串
configuration 如下
internal sealed class configuration : dbmigrationsconfiguration<hoteldbcontext> { public configuration() { // 自动迁移 true code frist automaticmigrationsenabled = true; } protected override void seed(hoteldbcontext context) { context.tsm_admin.addorupdate( p => p.userid, new tsm_admin1111111111111 { userid = "1", username = "111" }, new tsm_admin1111111111111 { userid = "2", username = "222" }, new tsm_admin1111111111111 { userid = "3", username = "333" } ); } }
automaticmigrationsenabled 意思就是找不到数据库的时候自动创建数据库。顺带还会创建初始数据(表和数据)。在seed中
说真的很鸡肋.用的很想骂街
接下来是ef的各种使用方式。。婴儿教学版
new configuration(); using (var data = new hoteldbcontext()) { //查询.全表 var a = data.tsm_admin.tolist(); //插入 data.tsm_admin.add(new tsm_admin1111111111111 { userid = "高1030测试" }); data.savechanges(); //修改 var model = data.tsm_admin.where(b => b.userid == "高1030测试").first(); if (model != null) { model.username = "高1030测试名字"; data.entry<tsm_admin1111111111111>(model).state = system.data.entity.entitystate.modified; data.savechanges(); } //删除 var delete = data.tsm_admin.where(b => b.userid == "高1030测试").first(); if (delete != null) { var result = data.tsm_admin.where(b => b.userid == delete.userid).firstordefault(); data.tsm_admin.remove(result); data.savechanges(); } var select = data.database.sqlquery<tsm_admin1111111111111>("select * from tsm_123 ").tolist(); var insert = data.database.executesqlcommand("insert into tsm_admin(userid) values('高1030测试')"); }
能用dapper。就别用ef..
attribute。
很多人都梦想着自定义属于自己的属性.那么
我用双手成就你的梦想
stringlength是自定义属性的名字attribute是必须加上去的。并且在使用中会被忽视
[attributeusage(attributetargets.property)] public class stringlengthattribute : attribute { private int _maximumlength; public stringlengthattribute(int maximumlength) { _maximumlength = maximumlength; } public int maximumlength { get { return _maximumlength; } } }
接下来定义使用的实体
public class people { [stringlength(8)] public string name { get; set; } [stringlength(15)] public string description { get; set; } }
接下来定义获取属性内容的方法
public class validationmodel { public void validate(object obj) { var t = obj.gettype(); //由于我们只在property设置了attibute,所以先获取property var properties = t.getproperties(); foreach (var property in properties) { //这里只做一个stringlength的验证,这里如果要做很多验证,需要好好设计一下,千万不要用if elseif去链接 //会非常难于维护,类似这样的开源项目很多,有兴趣可以去看源码。 if (!property.isdefined(typeof(stringlengthattribute), false)) continue; var attributes = property.getcustomattributes(false); foreach (var attribute in attributes) { //这里的maximumlength 最好用常量去做 var maxinumlength = (int)attribute.gettype(). getproperty("maximumlength"). getvalue(attribute); //获取属性的值 var propertyvalue = property.getvalue(obj) as string; if (propertyvalue == null) throw new exception("exception info");//这里可以自定义,也可以用具体系统异常类 if (propertyvalue.length > maxinumlength) throw new exception(string.format("属性{0}的值{1}的长度超过了{2}", property.name, propertyvalue, maxinumlength)); } } } }
接下来是调用过程
var people = new people() { name = "qweasdzxcasdqweasdzxc", description = "description" }; try { new validationmodel().validate(people); } catch (exception ex) { console.writeline(ex.message); }
这个段子充分解释了如何使用自定义attribute
核心思想是万物皆可supreme
httpruntime.cache
开发中很多不常改动的数据。可以考虑将数据从数据库里取出来后的指定时间内存在本地内存中
using system; using system.web; using system.web.caching; namespace chinamoney.core { public class cachehelper { /// <summary> /// 获取数据缓存 /// </summary> /// <param name="cachekey">键</param> public static object getcache(string cachekey) { var objcache = httpruntime.cache.get(cachekey); return objcache; } /// <summary> /// 设置数据缓存 /// </summary> public static void setcache(string cachekey, object objobject) { var objcache = httpruntime.cache; objcache.insert(cachekey, objobject); } /// <summary> /// 设置数据缓存 /// </summary> public static void setcache(string cachekey, object objobject, int hours) { try { if (objobject == null) return; var objcache = httpruntime.cache; //相对过期 //objcache.insert(cachekey, objobject, null, datetime.maxvalue, timeout, cacheitempriority.notremovable, null); //绝对过期时间 objcache.insert(cachekey, objobject, null, datetime.now.addhours(hours), timespan.zero, cacheitempriority.high, null); } catch (exception e) { log.logger.log("缓存写入异常:",e); } } /// <summary> /// 移除指定数据缓存 /// </summary> public static void removeallcache(string cachekey) { var cache = httpruntime.cache; cache.remove(cachekey); } /// <summary> /// 移除全部缓存 /// </summary> public static void removeallcache() { var cache = httpruntime.cache; var cacheenum = cache.getenumerator(); while (cacheenum.movenext()) { cache.remove(cacheenum.key.tostring()); } } } }
读取
cachehelper.getcache("cacheextraterritorial") as list<extraterritorialdataentity>;
写入
cachehelper.setcache("cacheextraterritorial", enumerable, result.count);
清空全部缓存(带名称清理指定缓存,不带名称清理全部缓存)
cachehelper.removeallcache("cacheextraterritorial");
ad是微软推出的又一款对象数据库,
集成了权限和员工信息。
在此贴出ad操作的helper
using chinamoney.core.log; using system; using system.collections; using system.directoryservices; namespace chinamoney.core { /// <summary> /// ad域 /// </summary> public class adhelper { /// <summary> /// 获取单个用户 /// </summary> /// <param name="user"></param> /// <returns></returns> public static directoryentry getone(string ldap, string user, string password, string search) { try { directoryentry entry = new directoryentry(ldap, user, password); directorysearcher searcher = new directorysearcher(entry); //searcher.filter = "(&(objectclass=user)(samaccountname=" + search + "))";//不支持中文名.改成全局搜索. searcher.filter = "(&(objectcategory=person)(objectclass=user))"; searchresultcollection result = searcher.findall(); foreach (searchresult item in result) { icollection serach = item.properties.propertynames; foreach (var model in serach) { if (model.tostring() == "name")//邮件中文名 ad name { if (item.properties["name"][0].tostring() == search) { return item.getdirectoryentry(); } } } } entry.close(); //return null; } catch (exception e) { logger.log("ad同步异常信息.异常信息:", e); } return null; } /// <summary> /// 获取全部用户 /// </summary> /// <param name="ldap"></param> /// <param name="user"></param> /// <param name="password"></param> /// <returns></returns> public static searchresultcollection getall(string ldap, string user, string password) { try { using (directoryentry objde = new directoryentry(ldap, user, password)) { string strfilter = "(&(objectcategory=person)(objectclass=user))"; using (directorysearcher objsearcher = new directorysearcher(objde, strfilter)) { // strfilter = "(objectguid=*)"; // directorysearcher objsearcher = new directorysearcher(objde, strfilter); return objsearcher.findall(); } } //directoryentry objde = new directoryentry(ldap, user, password);//("ldap://cftes.org", @"cftes\admin", "pass@123"); } catch (exception e) { logger.log("ad同步异常信息.异常信息:", e); } return null; } /// <summary> /// 禁用指定用户 /// </summary> /// <param name="entry"></param> public static void disableuser(directoryentry entry) { if (entry != null) { using (directoryentry de = entry) { int control = (int)(de.properties["useraccountcontrol"][0]); control = control | (int)(ads_user_flag_enum.ads_uf_accountdisable); de.properties["useraccountcontrol"].value = control; de.commitchanges(); } } } /// <summary> /// 用户属性定义标志 /// </summary> [flags] public enum ads_user_flag_enum : int { /// <summary> /// 登录脚本标志。如果通过 adsi ldap 进行读或写操作时,该标志失效。如果通过 adsi winnt,该标志为只读。 /// </summary> ads_uf_script = 0x0001, /// <summary> /// 用户帐号禁用标志 /// </summary> ads_uf_accountdisable = 0x0002, /// <summary> /// 主文件夹标志 /// </summary> ads_uf_homedir_required = 0x0008, /// <summary> /// 过期标志 /// </summary> ads_uf_lockout = 0x0010, /// <summary> /// 用户密码不是必须的 /// </summary> ads_uf_passwd_notreqd = 0x0020, /// <summary> /// 密码不能更改标志 /// </summary> ads_uf_passwd_cant_change = 0x0040, /// <summary> /// 使用可逆的加密保存密码 /// </summary> ads_uf_encrypted_text_password_allowed = 0x0080, /// <summary> /// 本地帐号标志 /// </summary> ads_uf_temp_duplicate_account = 0x0100, /// <summary> /// 普通用户的默认帐号类型 /// </summary> ads_uf_normal_account = 0x0200, /// <summary> /// 跨域的信任帐号标志 /// </summary> ads_uf_interdomain_trust_account = 0x0800, /// <summary> /// 工作站信任帐号标志 /// </summary> ads_uf_workstation_trust_account = 0x1000, /// <summary> /// 服务器信任帐号标志 /// </summary> ads_uf_server_trust_account = 0x2000, /// <summary> /// 密码永不过期标志 /// </summary> ads_uf_dont_expire_passwd = 0x10000, /// <summary> /// mns 帐号标志 /// </summary> ads_uf_mns_logon_account = 0x20000, /// <summary> /// 交互式登录必须使用智能卡 /// </summary> ads_uf_smartcard_required = 0x40000, /// <summary> /// 当设置该标志时,服务帐号(用户或计算机帐号)将通过 kerberos 委托信任 /// </summary> ads_uf_trusted_for_delegation = 0x80000, /// <summary> /// 当设置该标志时,即使服务帐号是通过 kerberos 委托信任的,敏感帐号不能被委托 /// </summary> ads_uf_not_delegated = 0x100000, /// <summary> /// 此帐号需要 des 加密类型 /// </summary> ads_uf_use_des_key_only = 0x200000, /// <summary> /// 不要进行 kerberos 预身份验证 /// </summary> ads_uf_dont_require_preauth = 0x4000000, /// <summary> /// 用户密码过期标志 /// </summary> ads_uf_password_expired = 0x800000, /// <summary> /// 用户帐号可委托标志 /// </summary> ads_uf_trusted_to_authenticate_for_delegation = 0x1000000 } } }
调用方式
searchresultcollection data = adhelper.getall(ldap, @name, password);
禁用账号
adhelper.disableuser(adhelper.getone(ldap, name, password, serach.chinaname));
list<t>根据指定字段去重
list<string>去重很容易distinct就可以
如果是list<t>在实体中根据指定字段判断重复项.如果每次都写循环是不是很累.
在此贴出帮助类
using system.collections.generic; namespace chinamoney.core { /// <summary> /// 去除重复项 /// </summary> /// <typeparam name="t"></typeparam> /// <param name="x"></param> /// <param name="y"></param> /// <returns></returns> public delegate bool equalscomparer<t>(t x, t y); public class comparerhelper<t> : iequalitycomparer<t> { private equalscomparer<t> _equalscomparer; public comparerhelper(equalscomparer<t> equalscomparer) { this._equalscomparer = equalscomparer; } public bool equals(t x, t y) { if (null != this._equalscomparer) return this._equalscomparer(x, y); else return false; } public int gethashcode(t obj) { return obj.tostring().gethashcode(); } } }
调用方式
rows = rows.distinct(new comparerhelper<extraterritorialdatadto>((x, y) => (null != x && null != y) && (x.senderaddress == y.senderaddress))).tolist();
拉姆达指定的字段就是不能相同的字段,可以根据情景变化
jquerycache
cookie有长度限制4m,
如果真的有大量数据要存放在客户端jquery.cache 是个不错的考虑
<script src="/webstoragecache/web-storage-cache.js"></script> <script src="/webstoragecache/ajax-cache.js"></script> var wscache = new webstoragecache();//缓存对象.全局通用
wscache.issupported() //当前浏览器是否支持缓存 wscache.clear();//清空所有缓存 wscache.set('键', 值, { exp: 时间.单位秒。整数 });
wscache.get('键')
缓存插入成功后可以再浏览器中看到(开发者工具)
i18n
<script src="~/scripts/jquery-3.3.1.js"></script> <script src="~/scripts/jquery.json.min.js"></script> <script src="~/scripts/jquery.i18n.properties.js"></script>
html
<div>
<p id="text"></p>
<button onclick="switchlang()" id="lang"></button>
</div>
script
<script>
var language_code = "en_us"; //标识语言
function loadproperties(type) {
jquery.i18n.properties({
name: 'strings', // 资源文件名称
path: 'static/', // 资源文件所在目录路径
mode: 'map', // 模式:变量或 map
language: type, // 对应的语言
cache: false,
encoding: 'utf-8',
callback: function () { // 回调方法
$('#text').html($.i18n.prop('string_text'));
$('#lang').html($.i18n.prop('string_lang'));
}
});
}
function switchlang() {
language_code = language_code == 'zh_cn' ? 'en_us' : 'zh_cn';
loadproperties(language_code);
}
$(document).ready(function () {
language_code = jquery.i18n.normaliselanguagecode({}); //获取浏览器的语言
loadproperties(language_code);
})
</script>
来一顿专业的bb压压惊
在html中需要设置多国语言的元素上添加id
properties.name+ language_code 就是当前加载的语种文件
如果需要改变语言的话
赋值 language_code
重新加载 loadproperties(language_code);
页面无刷新喔
完美
html 自定义属性 data-xx
html允许我们自定义的属性.都以data-开头
举个栗子
再js中或者直接写html
html += "<li class='cl' dataurl='" + data[i].content + "' datatitle='" + data[i].title + "' datadesc='" + data[i].describe + "' time='" + data[i].showtime + "'>"; $('#coursedata').append($(html));
栗子中是dataurl,datatitle,datadesc
dataurl或者data-url并没有什么区别。
因为data-xx 浏览器会认为是用户自定义属性。不做任何处理
至于dataxx浏览器根本不认识。所以也不做任何处理
大概就是我开心就好的意思
读 var dataurl = $(this).attr("dataurl");
写 $("div").attr("data-my-value", "使用attr改变的数据");