匯總小程式開發中遇到的問題

coldplay.xixi
發布: 2021-04-06 11:24:59
轉載
2209 人瀏覽過

匯總小程式開發中遇到的問題

小程式面試題

1、bindtap和catchtap的差別是什麼?

bind事件綁定不會阻止冒泡事件向上冒泡,catch#事件綁定定可以阻止冒泡事件向上冒泡

2、Js陣列轉成換字串,強制轉換成整數及轉換成浮點數的函數分別是什麼?

js提供了parseInt()和parseFloat()兩個轉換函數。前者把數值轉換成整數,後者則將數值轉換成浮點數。只有對String類型呼叫這些方法,這兩個函數才能正確運作;對其他類型回傳的都是NaN(Not a Number)。

相關免費學習推薦:微信小程式開發

1、轉換函數:

在判斷字串是否為數字值前,parseInt()和parseFloat()都會仔細分析字串。 parseInt()方法首先查看位置0處的 字符,判斷它是否是個有效數字;如果不是,則該方法將返回NaN,不再繼續執行其他操作。但如果該字符是有效數字,則該方法將查看位置1處的字符,進行相同的 測試。這個過程將持續到發現非有效數字的字元為止,此時parseInt()將把該字元之前的字串轉換成數字。

parseInt("1234blue"); //returns 1234 
parseInt("0xA"); //returns 10 
parseInt("22.5"); //returns 22 
parseInt("blue"); //returns NaN
登入後複製

2. 強制型別轉換

#也可使用強制型別轉換(type casting)處理轉換值的類型。使用強制類型轉換可以存取特定的值,即使它是另一種類型的。
ECMAScript中可用的3種強制型別轉換如下: 
Boolean(value)-將給定的值轉換成Boolean型; 
#Number(value)——把給定的值轉換成數字(可以是整數或浮點數); 
String(value)——把給定的值轉換成字符串。

3. 利用js變數弱型別轉換

#舉個小例子,一看,就會明白了。

<script> 
var str= &#39;012.345 &#39;; 
var x = str-0; 
x = x*1;
</script>
登入後複製

上例利用了js的弱型別的特點,只進行了算術運算,實現了字串到數字的型別轉換,不過這個方法還是不推薦的。

3、簡單描述下微信小程式的相關檔案類型

小程式:pages -index:index.js(頁面邏輯) /index.wxml (頁面結構)/index.wxss (頁面樣式表) / index.json (頁面設定)

App.js   小程式邏輯

App.json  小程式公共設定

App.wxss   小型程式公共樣式表

4、##小程式有哪些參數傳值的方法?

1、設定id的方法標識跳轉後傳遞的參數值;

2、透過使用data - xxxx 的方法來識別要傳遞的值

微信小程式設定id的方法標識來傳值

在要跳轉的item處,設定一個id並給目前的id賦值上對應的key值,例如一部電影的id(後面帶著id去下一個頁面查詢,詳細資訊)如:

後我們在js的bindtap的回應事件中獲取,並傳遞到下一個介面中;

取得到id傳的值

#透過e.currentTarget.id;取得設定的id值,並透過設定全域物件的方式傳遞數值,
取得全域物件
 var app=getApp(); //設定全域的請求存取傳遞的參數 app.requestDetailid=id;

提示:其實我們也可以在,wxml中查看到我們設定的每一個item的id值

通过使用data - xxxx 的方法标识来传值

通过使用data - xxxx 的方法标识来传值,xxxx可以自定义取名 比如data-key等等都可以。

如何获取data-xxxx传递的值?

在js的bindtap的响应事件中:

通过数据解析一层层找到数据,var id=e.target.dataset.id(根据你的data-id的取名)

微信小程序如何跨页面获取值?

依据上面的方式设置要传递的值,页面跳转后,我们就需要在下一个页面拿到传递的数据(这个数据在传递前,就已经被设置成全局变量

在跳转后的js页面,接收传递过来的数据detail.js

同样通过全局额方式取值出来,(即和app.js中取某个变量的值是一样的)

var movieid=getApp().MovieDetailid;
console.log(movieid);

5、简述下wx.navigateTo(), wx.redirectTo(), wx.switchTab(), wx.navigateBack(), wx.reLaunch()的区别?

微信小程序 跳转页面

小程序页面有2种跳转,可以在wxml页面或者js中:

1,在wxml页面中:

<navigator url="../index/index">跳转到新页面</navigator>
<navigator url="../index/index" open-type="redirect">在当前页打开</navigator>
<navigator url="../index/index" open-type="switchTab">切换到首页Tab</navigator>
登入後複製

2,在js页面中:

【注意】此处注意两个关键词 “应用内的页面” 和 “tabBar页面”。 app.json文件中tabBar中注册过的tab页,即为“tabBar页面”,非tabBar中注册占用的页面即为“应用内的页面” 。 如下图:home页面为“应用内的页面”,index和logs页面则为 “tabBar页面”。

3,如果上述跳转遇到跳转失败或无效的问题,请访问下面链接:

wx.navigateTo/wx.redirectTo 无效

6、如果需要用户授权,用户选择拒绝授权,此时应该如何处理?

在微信小程序开发时,当我们调用API wx.getUserInfo(OBJECT) 时,需要用户授权。但如果用户拒绝授权,我们如何兼容用户拒绝授权状态,拥有更好的用户体验呢?

先看看这个接口的官方文档:

wx.getUserInfo(OBJECT)

获取用户信息,需要先调用 wx.login 接口。

OBJECT参数说明:

参数名

类型

必填

说明

withCredentials

Boolean

是否带上登录态信息

success

Function

接口调用成功的回调函数

fail

Function

接口调用失败的回调函数

complete

Function

接口调用结束的回调函数(调用成功、失败都会执行)

1. tip: wx.getUserInfo 接口需要用户授权,请兼容用户拒绝授权的场景。

我们就是要在用户点击拒绝的时候,弹出提示框,提示用户以提升用户体验。像下面这样的。

用具体代码实现就是,将弹窗写在 wx.getUserInfo 的fail回调函数中,像下面这样:

wx.getUserInfo({
success: function (resuser) {
console.log(success)
},
fail: function () {// 调用微信弹窗接口
wx.showModal({
title: &#39;警告&#39;,
content: &#39;您点击了拒绝授权,将无法正常使用******的功能体验。请10分钟后再次点击授权,或者删除小程序重新进入。&#39;,
success: function (res) {
if (res.confirm) {
console.log(&#39;用户点击确定&#39;)
}
}
})
}
})
登入後複製

这样用户就获得了提示信息,但此时,用户还是停留在页面的,如果某些展示信息,还是给要给用户展示的,只是在进行某些操作的时候要对授权进行验证的话,那就得继续修改我们的代码,保存用户的登录态,在其他地方做验证使用。

第一种思路:

保存登录态这里是这样的,将用户的登录信息传给后台,后台保存用户信息,同时用 open_id 在后台换取一个SessionId 用换取的这个SessionId 存在缓存,做为登录态验证。

wx.getUserInfo({
success: function (resuser) {
let userInfo = resuser.userInfo
that.healthApi.login(code, userInfo).then(logindata => {   // 这里将微信的请求封装成Promiese 风格
if (logindata.code === 0) {
var sessionId = logindata.data// 调用微信wechat.setStorage将换回来的 SessionId 存在本地缓存
that.wechat.setStorage(&#39;sessionId&#39;, sessionId).then(() => {
that.globalData.userInfo = userInfo
typeof cb == "function" && cb(that.globalData.userInfo)
})
}
})
},
fail: function () {
wx.showModal({
title: &#39;警告&#39;,
content: &#39;您点击了拒绝授权,将无法正常使用*****的功能体验。请10分钟后再次点击授权,或者删除小程序重新进入。&#39;,
success: function (res) {
if (res.confirm) {
console.log(&#39;用户点击确定&#39;)
}
}
})
}
})
登入後複製

这样我们将登录态保存在了 SessionId 中,在每次登录的时候我们只需要再调用一个 检查 SessionId的接口就行,检查不通过再调微信登录接口。此处不做延伸了。

第二种思路:

在3.29微信小程序更新的版本中,加入了这样一条属性

withCredentials 字段基础库版本 1.1.0 开始支持,低版本需做兼容处理

这个字段的意思就是调用 wx.getUserInfo(OBJECT) 是否带上 登录态 的信息。

官方文档是这样解释的:

withCredentials 字段基础库版本 1.1.0 开始支持,低版本需做兼容处理

注:当 withCredentials 为 true 时,要求此前有调用过 wx.login 且登录态尚未过期,此时返回的数据会包含 encryptedData, iv 等敏感信息;当 withCredentials 为 false 时,不要求有登录态,返回的数据不包含 encryptedData, iv 等敏感信息。

success返回参数说明:

参数

类型

说明

userInfo

OBJECT

用户信息对象,不包含 openid 等敏感信息

rawData

String

不包括敏感信息的原始数据字符串,用于计算签名。

signature

String

使用 sha1( rawData + sessionkey ) 得到字符串,用于校验用户信息。

encryptedData

String

包括敏感数据在内的完整用户信息的加密数据,详细见加密数据解密算法

iv

String

加密算法的初始向量,详细见加密数据解密算法

注:需要兼容微信低版本,向后兼容

那么利用这个接口,我们可以直接拿到 登录状态,在其他需要验证登录的地方进行提示,而在不需要授权的地方还可以让用户浏览小程序。

回到前面的问题,在用户点击拒绝授权后,在某些操作时需要验证用户是否授权过,弹出交互信息,那么就利用上面的 SessionId或者 withCredentials 登录态进行下面的操作:

applyIn: function applyIn() {
if (wx.getStorageSync(&#39;sessionId&#39;)) {  // 根据储存的sessionId 进行验证
wx.navigateTo({
url: &#39;familyDoctorApply/familyDoctorApply?Oid=&#39; + this.data.params.Oid + &#39;&title=&#39; + this.data.params.title + &#39;&serviceCity=&#39; + this.data.array[this.data.index].name + &#39;&productPrice=&#39; + this.data.product.productPrice
});
} else {
wx.showModal({
title: &#39;警告&#39;,
content: &#39;您点击了拒绝授权,无法使用此功能。&#39;,
success: function (res) {
if (res.confirm) {
console.log(&#39;用户点击确定&#39;)
}
}
})
}
登入後複製

效果像这样:

这样一个简单完整的登录及授权,登录态保存等前端微信小程序解决方案就完成了,还可以继续扩展到登录有效期,退出登录,用户权限等跟多扩展的地方。

7、你平时封装可以复用的方法吗?你会把可以复用的方法写在哪个文件里?

其实可以模拟一些框架的,比如bootsrap,写个demo出来,抽出css和js,js最好抽象成对象(构造函数)或者是带参数的方法,然后你只要声明对像,或者参数指定某个class或id,就可以了

写在html文件里有什么优点吗?
独立出来会有什么问题吗?尤其是载入页面的时候,应该会多发很多http请求吧,会不会造成加载变慢?

8、分析下小程序的优劣势?

小程序是在微信生态发展过程中新出现的一种应用形态,小程序的小,从某种程度上已经说明了它的体量不会很大,但是可以实现一些功能相对简单、交互相对简单的服务需求,同时解决了App长期以来多平台适配、多应用市场分发、开发成本居高不下等诸多方面的问题。所以小程序【密件】依靠微信平台和自身“阅后即焚”的功能,获得众多年轻人的好评

优势:

1)容易上手,只要之前有HTML+CSS+JS基础知识,写小程序基本上没有大问题;当然如果了解ES6+CSS3则完全可以编写出即精简又动感的小程序;

2)基本上不需要考虑兼容性问题,只要微信可以正常运行的机器,就可以运行小程序;

3)基本组件库已经比较齐全:Toast,Loading框,Picker,定位及地图,Image,Input,Checkbox,Text,TextArea,ScrollView等常用的组件都有,而且使用也挺简单、方便;

4)发布、审核高效,基本上上午发布审核,下午就审核通过,升级简单,而且支持灰度发布;

5 ) 微信官方提供使用人数、频率等数据统计,小程序js脚本执行错误日志;

6)开发文档比较完善,开发社区比较活跃;

7)最近刚开放的牛x功能,新增webview组件,可以展示网页啦,这个比较爽;

8)支持插件式开发,一些基本功能可以开发成插件,供多个小程序调用;

劣势:

1)后台调试麻烦,因为API接口必须https请求,且公网地址,也就是说后台代码必须发布到远程服务器上;当然我们可以修改host进行dns映射把远程服务器转到本地,或者开启tomcat远程调试;不管怎么说终归调试比较麻烦。

2)前台测试有诸多坑,最头疼莫过于模拟器与真机显示不一致(之前碰到一个案例,后续单独讲解)

3)真机测试,个别功能安卓和苹果表现迥异,我们的小程序里有很多页面有定位功能,模拟器和iphone定位瞬间完成,然而安卓手机就蛋疼了,老显示“定位中...”要很久才能定位好。后来没办法只能优化,减少定位次数。

4)native组件,展示很不好,比如textarea,不能在滚动页面出现,而且至于顶层,经常其它组件会被它遮挡,点击其它组件时,就进入textarea输入框;画布组件也是如此;

5)页面跳转深度不能超过5个页面,这个比较麻烦,有些复杂的页面跳转没法实现,不过太复杂的话也有悖小程序简单易用的原则啦;

6)小程序升级问题,官方文档说会自动更新,实际情况往往是要先把原来的小程序删除掉,重新搜索添加,才能加载最新版本;

7)页面渲染稳定性有待提高,已经好几次出现部分用户的页面显示异常,整个页面被放大了好几倍,先删除原来小程序再添加回来,如此重复好几次,才能显示正常;

8)js引用只能使用绝对路径,很蛋疼;基于安全性及MINA框架实现原理,小程序中对js使用做了很多限制,不能使用:new Function,eval,Generator,不能操作cookie,不能操作DOM;

9)开发工具bug比较多且效率比较低,三天两头升级,解决老问题的同时又出现问题;文件查找、资源定位、代码编辑较eclipse有一定差距。经常出现把a.js当做b.js来修改

9、设置值到页面暂存区(即data)里面的方法有几种?分别是什么?有什么区别?

1. 使用QueryString变量
QueryString是一种非常简单的传值方式,他可以将传送的值显示在浏览器的地址栏中。如果是传递一个或多个安全性要求不高或是结构简单的数值时,可以使用这个方法。但是对于传递数组或对象的话,就不能用这个方法了。下面是一个例子:
a.aspx的C#代码

private void Button1_Click(object sender, System.EventArgs e) 
{ 
 string s_url; 
 s_url = "b.aspx?name=" + Label1.Text; 
 Response.Redirect(s_url); 
} 
b.aspx中C#代码 
private void Page_Load(object sender, EventArgs e) 
{ 
 Label2.Text = Request.QueryString["name"]; 
}
登入後複製

2. 使用Application 对象变量
Application对象的作用范围是整个全局,也就是说对所有用户都有效。其常用的方法用Lock和UnLock。
a.aspx的C#代码

private void Button1_Click(object sender, System.EventArgs e) 
{ 
 Application["name"] = Label1.Text; 
 Server.Transfer("b.aspx"); 
} 
b.aspx中C#代码 
private void Page_Load(object sender, EventArgs e) 
{ 
 string name; 
 Application.Lock(); 
 name = Application["name"].ToString(); 
 Application.UnLock(); 
}
登入後複製

3. 使用Session变量
想必这个肯定是大家使用中最常见的用法了,其操作与Application类似,作用于用户个人,所以,过量的存储会导致服务器内存资源的耗尽。
a.aspx的C#代码

private void Button1_Click(object sender, System.EventArgs e) 
{ 
 Session["name"] = Label.Text; 
} 
b.aspx中C#代码 
private void Page_Load(object sender, EventArgs e) 
{ 
 string name; 
 name = Session["name"].ToString(); 
}
登入後複製

4. 使用Cookie对象变量
这个也是大家常使用的方法,与Session一样,其是什对每一个用户而言的,但是有个本质的区别,即Cookie是存放在客户端的,而session是存放在服务器端的。而且Cookie的使用要配合ASP.NET内置对象Request来使用。
a.aspx的C#代码

private void Button1_Click(object sender, System.EventArgs e) 
{ 
 HttpCookie cookie_name = new HttpCookie("name"); 
 cookie_name.Value = Label1.Text; 
 Reponse.AppendCookie(cookie_name); 
 Server.Transfer("b.aspx"); 
} 
b.aspx中C#代码 
private void Page_Load(object sender, EventArgs e) 
{ 
 string name; 
 name = Request.Cookie["name"].Value.ToString(); 
}
登入後複製

5. 使用Server.Transfer方法
这个才可以说是面象对象开发所使用的方法,其使用Server.Transfer方法把流程从当前页面引导到另一个页面中,新的页面使用前一个页面的应答流,所以这个方法是完全面象对象的,简洁有效。
a.aspx的C#代码

public string Name 
{ 
 get{ return Label1.Text;} 
} 
private void Button1_Click(object sender, System.EventArgs e) 
{ 
 Server.Transfer("b.aspx"); 
} 
b.aspx中C#代码 
private void Page_Load(object sender, EventArgs e) 
{ 
 a newWeb; //实例a窗体 
 newWeb = (source)Context.Handler; 
 string name; 
 name = newWeb.Name; 
}
登入後複製

微信小程序--data的赋值与取值

通过小程序官方文档可知:

Page() 函数用来注册一个页面。接受一个 object 参数,其指定页面的初始数据、生命周期函数、事件处理函数等。其中的参数data用来设置初始数据,WXML 中的动态数据均来自对应 Page 的 data。

所以如果页面需要显示动态数据必须要把数据更新到data中对应的变量中。

页面js文件中这么写:

Page({
  data: {
    message: &#39;Hello MINA!&#39;
  }
})
· wxml中这么写:
<view> {{ message }} </view>
登入後複製

如果该数据在操作过程中发生变化,需要将新数据重新绑定到该变量中,写法如下:

function setData(){
    var that = this;
    that.setData({
      message: &#39;新消息&#39;
    })
}
登入後複製

如果想在js文件中使用data中的数据写法如下:

function getData(){
    var that = this;
    console.log(that.data.message)
}
登入後複製

10、如何检测用户的微信版本是否支持某项功能?

第一期開放的接口,不是不能使用,而是無需檢測,全部都是支援的。
只有後面最新開放的一些接口,才需要偵測是否支援。
目前開放的所有介面:
onMenuShareTimeline
onMenuShareAppMessage
##onMenuShareQQ
#onMenuShareWeibo
onMenuShareQZone
#startRecord
stopRecord
#onVoiceRecordEndstopRecord
#onVoiceRecordEnd
playVoice
pauseVoice
stopVoice
onVoicePlayEnd
#uploadVoice
downloadVoice
chooseImage
#previewImage
uploadImage
#downloadImage
translateVoice
getNetworkType
openLocation
getLocation
hideOptionMenu
#showOptionMenu
hideMenuItems
#showMenuItems
##hideAllNonBaseMenuItem
##showAllNonBaseMenuItem#hideAllNonBaseMenuItem
##showAllNonBaseMenuItem
#closeWindow
scanQRCode
chooseWXPay
openProductSpecificView
#addCard

openProductSpecificView

#addCardchooseCard

openCard 







#11、
如何分包載入?分包加載的優勢在哪?

分包載入的介紹
#      大部分小程式都會由某個功能組成,通常是這幾個功能之間是獨立的,但會依賴一些公共的邏輯,而這些功能通常會對應某幾個獨立的頁面。那麼小程式碼的打包,大可不必一定要打成一個,可以依照功能的劃分,拆分成幾個分包,當需要用到某個功能時,才載入這個功能對應的分包。
對使用者來說,小程式載入流程變成了:
1.第一次啟動時,先下載小程式主包,顯示主包內的頁面;

2.如果使用者進入了某個分包的頁面,再下載這個對應分包,下載完畢後,顯示分包的頁面。 #########採用分包加載,對開發者而言,能使小程式有更大的程式碼體積,承載更多的功能與服務;而對用戶而言,可以更快地打開小程序,同時在不影響啟動速度前提下使用更多功能。 ############分包的劃分############在配置前首先需要開發者規劃下各個分包需要容納的內容,我們建議開發者按照功能劃分的的原則,將同一個功能下的頁面和邏輯放置於同一個目錄下,對於一些跨功能之間公共邏輯,將其放置於主包下,這樣可以確保在分包引用這部分功能時,這部分的邏輯一定存在。 #########在分包分割時,應該注意以下事項:#########1.避免分包與分包之間引用上的耦合。因為分包的載入是由使用者操作觸發的,並不能確保某分包載入時,另外一個分包就一定存在,這個時候可能會導致JS 邏輯異常的情況,例如報「"xxx.js" is not defined」這樣的錯誤;#########2.一些公用到的自訂元件,需要放在主套件內。 ############分包的配置############      當理清了分包的分割後,就可以進行分包的配置了,這一步​​並不複雜。 ######

假设支持分包的小程序目录结构如下:

开发者通过在 app.json subPackages 字段声明项目分包结构:

分包加载的低版本兼容问题
微信 6.6.0 版本开始支持分包加载,而对于低于这个版本的客户端,我们做了兼容处理,开发者不需要对老版本微信客户端做兼容。对于老版本的客户端,编译后台会将所有的分包打包成一个整包,老版本的客户端依然按照整包的方式进行加载。
所以在老版本的微信客户端下,是依然采取整包加载的方式加载的,建议开发者尽量控制代码包的大小。
目前小程序分包大小的限制:
整个小程序所有分包大小不超过 4M
单个分包/主包大小不能超过 2M
随着时间推移,老版本覆盖率降低,我们会考虑进一步扩大代码包的大小。

12、在你开发小程序的过程中遇到过什么坑? 你是怎么解决的?

1.我们使用app.json文件来对微信小程序进行全局配置,决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 的时候在pages中写注释的时候回报错。
例如:

{
  "pages":[
      //这是首页面
    "pages/welcome/welcome"
  ]}
登入後複製

此时就会报错


2.在json文件中没有写内容的时候也要加一对大括号{ },不然的话也会报错

3. ①在开发微信小程序的时候,我们使用app.json文件来对微信小程序进行全局配置,决定页面文件的路径,窗口表现,设置网络超时时间,设置多Tab等。
以下是一个包含了所有配置选项的简单配置,app.json :

{
  //设置页面路径
  "pages": [
    "pages/index/index",
    "pages/logs/index"
  ],
  //设置默认页面的窗口表现
  "window": {
    "navigationBarTitleText": "Demo"
  },
  //设置底部 tab 的表现
  "tabBar": {
    "list": [{
      "pagePath": "pages/index/index",
      "text": "首页"
    }, {
      "pagePath": "pages/logs/logs",
      "text": "日志"
    }]
  },
  //设置网络超时时间
  "networkTimeout": {
    "request": 10000,
    "downloadFile": 10000
  },
  //设置是否开启 debug 模式
  "debug": true
}
登入後複製

②但是在对页面json文件进行配置的时候只可以配置设置默认页面的窗口表现(即只能对window进行配置),但是在此时可以直接省略window,如果加window则没有效果,也不会报错。
以下是一个包含了window配置选项的简单配置,post.json :

注意:这是错误的写法

{
  "window":{
    "navigationBarBackgroundColor": "#ffffff",
    "navigationBarTextStyle": "black",
    "navigationBarTitleText": "微信接口功能演示",
    "backgroundColor": "#eeeeee",
    "backgroundTextStyle": "light"
  }}
登入後複製

注意:正确的写法

{
    "navigationBarBackgroundColor": "#ffffff",
    "navigationBarTextStyle": "black",
    "navigationBarTitleText": "微信接口功能演示",
    "backgroundColor": "#eeeeee",
    "backgroundTextStyle": "light"}
登入後複製

4.此前一直没有注意vertical-align: middle和height:40rpx;line-height:40rpx进行设置垂直剧中的区别,这次主要说一下vertical-align: middle
代码如下:

<view class="post-author-date">
    <image class="post-author" src="../../images/avatar/1.png">
    </image>
    <text class="post-date">Nov 15 2016</text>
</view>
 
.post-author{
    width: 60rpx;
    height: 60rpx;
    vertical-align: middle;
}
.post-date{
    margin-top: 5rpx;
    vertical-align: middle;
    /*height: 40rpx;
    line-height: 40rpx;*/
}
登入後複製

总结: 
①vertical-align: middle;把此元素放在父元素的中部 
②当一个父元素里面有多个子元素,需要把几个子元素水平对齐,并且每个子元素都垂直剧中的时候,对每一个子元素进行设置 vertical-align: middle 
③height: 40rpx; line-height: 40rpx;可以对文本进行垂直居中

相关学习推荐:小程序开发教程

以上是匯總小程式開發中遇到的問題的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:csdn.net
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板