篇文章講到HTML炫酷的主流框架,今天小明就介紹一個HTML5功能的實現(xiàn)代碼
Introduce(介紹)
用戶簽到的H5例子(css+jquery,無圖片),由于網上找的的用戶簽到例子都不好,要不就是好多圖片組成的,要不就大量冗余代碼,所以特意做了個簽到界面(移動端)。
User sign sample page for mobile using h5 which only use css + jquery + html.
一些關鍵的地方
這個功能的編寫思路是,先構建日期和簽到相關數(shù)據(jù),然后從服務端獲取數(shù)據(jù),并對原有數(shù)據(jù)進行更改,最后進行渲染。
這樣子很好的擺脫了邏輯比較凌亂的問題,并且可以直接將這些數(shù)據(jù)用 vue.js 來掛載(本文沒有這樣做)。
生成日期數(shù)據(jù)
//生成日期數(shù)據(jù) function buildData() { var da = { dates: [],//日期數(shù)據(jù),從1號開始 current: '',//當前日期 monthFirst: 1,//獲取當月的1日等于星期幾 month: 0,//當前月份 days: 30,//當前月份共有多少天 day: 0,//今天幾號了 isSigned: false,//今天是否已經簽到 signLastDays:3,//連續(xù)簽到日子 signToday: function () { this.isSigned = true; this.dates[this.day].isSigned = true; }, }; var ds = []; //初始化日期數(shù)據(jù) var dt = new Date(); da.current = dt.ToString('yyyy年M月d日'); da.monthFirst = new Date(dt.getFullYear(), dt.getMonth(), 1).getDay(); da.month = dt.getMonth() + 1; da.days = new Date(dt.getFullYear(), parseInt(da.month), 0).getDate();//獲取當前月的天數(shù) da.day = dt.getDate(); for (var i = 1; i < da.days + 1; i++) { var o = { isSigned: false,//是否簽到了 num: i,//日期 isToday: i == da.day,//是否今天 isPass: i < da.day,//時間已過去 }; ds[i] = o; } da.dates = ds; return da; }
有了數(shù)據(jù)之后,就可以將數(shù)據(jù)轉換為界面了
//渲染數(shù)據(jù) function renderData(da) { var signDays = document.getElementById('spSignDays'); signDays.innerText = da.signLastDays; var root = document.getElementById("signTable"); root.innerHTML = ''; var tr, td; var st = da.monthFirst; var dates = da.dates; var rowcount = 0; //最多6行 for (var i = 0; i < 42; i++) { if (i % 7 == 0) { //如果沒有日期了,中斷 if (i > (st + da.days)) break; tr = document.createElement('tr'); tr.className = 'darkcolor trb'; root.appendChild(tr); rowcount++; } //前面或后面的空白 if (i < st || !dates[i - st + 1]) { td = document.createElement('td'); td.innerHTML = '<div class="sign-blank"><span></span></div>'; tr.appendChild(td); continue; } //填充數(shù)字部分 var d = dates[i - st + 1]; td = document.createElement('td'); var tdcss = ''; if (d.isToday) tdcss = 'sign-today'; else if (d.isPass) tdcss = 'sign-pass'; else tdcss = 'sign-future'; if (d.isSigned) { tdcss = 'sign-signed ' + tdcss; td.innerHTML = '<div class="' + tdcss + '"><span>' + d.num + '</span><svg xmlns="http://www.w3.org/2000/svg" version="1.1" class="sign-pin svg-triangle "><polygon points="0,0 35,0 0,35" /></svg></div>'; } else { tdcss = 'sign-unsign ' + tdcss; td.innerHTML = '<div class="' + tdcss + '"><span>' + d.num + '</span></div>'; } tr.appendChild(td); } //計算是否需要添加最后一行 if ((st + da.days + 1) / 7 > rowcount) root.appendChild(tr); } //構建日期數(shù)據(jù) var da = buildData(); //渲染 renderData(da);
以上就是本篇文章的全內容了
學習從來不是一個人的事情,要有個相互監(jiān)督的伙伴,想要學習或交流前端問題的小伙伴可以私信回復小明“學習” 獲取資料,一起學習!
于互聯(lián)網發(fā)展的今天,IT行業(yè)慢慢變成大多數(shù)年輕人發(fā)展的目標,不僅前景好,薪資也是越來越高的,而web前端是行業(yè)中需要的技術,也促進了大多數(shù)朋友在學習html5,今天小猿圈講師給你分享基于iview的router常用控制方式,在學的過程中不浪費時間少走彎路。
1、iview的router控制需求
最近在使用iview框架寫項目,遇到了一些路由控制上的問題,解決過程中也有一些心得,故在此記錄下來.
每個項目在開發(fā)時,對于類似tags(標簽頁)的控制需求都不盡相同,故以下先列出本文所述項目對標簽頁的控制要求(如有不同需求,本文當也可提供一些思路):
對于同名(name)的路由標簽頁,不能打開多個.譬如說從商品列表中打開商品展示標簽頁,如果已經有在打開的商品編輯頁面,則替換之.新打開的,未保存,已保存的標簽頁,同時只能存在一個(即不同params相同name的route只能有一個);
替換掉一個新的頁面時,通過切換的方式切換回來(先切到其他標簽頁再切換回來),仍是原來頁面的內容(即實際記錄的params在替換后應變化).類似的情況,還應包含單據(jù)從未保存到已保存,以及保存并新增功能;
2、基于vue的router控制
iview是基于vue的框架,故vue本身自帶的router控制方法是必然可行的.
vue變更路由的常用方式參考以下(該方法在官方api中有更詳細的介紹):
//變更當前路由(有歷史記錄,建議使用此方式)
this.$router.push({
name:'routerName',
params:routerParam
})
//變更當前路由(無歷史記錄)
this.$router.replace({
name:'routerName',
routerParam
})
官方路由變更確實可以正常打開標簽頁,但在實現(xiàn)1中所提到的各種需求的時候,就有些不滿足需求了.為此,需要參考3中,如何基于iview的outer控制.
3、基于iview的router控制
iview在控制路由的時候,使用vuex中的app.js來記錄標簽頁路由信息,如果對vuex還是很了解的話,可以通過這篇博文來先打一下基礎.
3.1如何實現(xiàn)需求1.1
想要實現(xiàn)不同params相同name的route在iview中只能有一個,關鍵是改變iview對路由相等的判斷方法,即'/src/libs/util.js'里的routeEqual方法:
/**
* @description 根據(jù)name/params/query判斷兩個路由對象是否相等
* @param {*} route1 路由對象
* @param {*} route2 路由對象
*/
export const routeEqual = (route1, route2) => {
return route1.name === route2.name
// 此處改變相同路由的判斷方式,改為name相同即認為相同
// const params1 = route1.params || {}
// const params2 = route2.params || {}
// const query1 = route1.query || {}
// const query2 = route2.query || {}
// return (route1.name === route2.name) && objEqual(params1, params2) && objEqual(query1, query2)
}
這里稍微解釋下(如果不關注原因,可以直接看3.2).當改變路由時,'src\components\main\main.vue'作為近乎頂層的組件控制著近乎所有的全局邏輯,其中就有對路由的監(jiān)控:
...
<side-menu
accordion
ref="sideMenu"
:active-name="$route.name"
:collapsed="collapsed"
@on-select="turnToPage"
:menu-list="menuList"
>
...
//此方法隸屬于methods,用以監(jiān)控side-menu的選擇事件,即平時從左側菜單打開標簽頁的邏輯
turnToPage (route) {
let { name, params, query } = {}
if (typeof route === 'string') name = route
else {
name = route.name
params = route.params
query = route.query
}
if (name.indexOf('isTurnByHref_') > -1) {
window.open(name.split('_')[1])
return
}
this.$router.push({
name,
params,
query
})
},
...
watch: {
// 檢測route的變化
$route (newRoute) {
const { name, query, params, meta } = newRoute
this.addTag({
route: { name, query, params, meta },
type: 'push'
})
this.setBreadCrumb(newRoute)
this.setTagNavList(getNewTagList(this.tagNavList, newRoute))
this.$refs.sideMenu.updateOpenName(newRoute.name)
}
},
...
從以上代碼可推測出,main.vue通過turnToPage方法實現(xiàn)打開標簽頁的邏輯,但方法內部并沒有體現(xiàn)便簽頁顯示效果變化(包含內部數(shù)據(jù)變化,以下同)的邏輯,這是由于顯示效果變化的邏輯,由對$router的監(jiān)控實現(xiàn).
這樣,不止從左側菜單打開新標簽頁可以實現(xiàn)顯示變化效果,其他只要使用vue的原版push等方法改變router的方法,均可監(jiān)測到.
逐步查看下各個方法,其中影響當前標簽頁顯示效果的,是'src/store/module/app.js'的addTag方法.
addTag (state, { route, type = 'unshift' }) {
let router = getRouteTitleHandled(route)
if (!routeHasExist(state.tagNavList, router)) {
if (type === 'push') state.tagNavList.push(router)
else {
if (router.name === homeName) state.tagNavList.unshift(router)
else state.tagNavList.splice(1, 0, router)
}
setTagNavListInLocalstorage([...state.tagNavList])
}
},
盡管方法內部仍調用了很多,其中一個很重要的判斷,就是routeHasExist(路由是否存在),這個方法也是判斷是否為相同標簽頁的一個關鍵節(jié)點(該方法同樣在util.js):
/**
* 判斷打開的標簽列表里是否已存在這個新添加的路由對象
*/
export const routeHasExist = (tagNavList, routeItem) => {
let len = tagNavList.length
let res = false
doCustomTimes(len, (index) => {
if (routeEqual(tagNavList[index], routeItem)) res = true
})
return res
}
明顯可以看出,這個方法內調用routeEqual,就是用以判斷是否為相同路由的實際方法(當然是通過比較新路由與已有路由進行比較),如此,僅需改變routeEqual即可.
以防萬一,全局搜索下調用這個routeEqual的所有方法,發(fā)現(xiàn)所有調用的地方再routeEqual在改變后不會出現(xiàn)新的問題.
3.2如何實現(xiàn)需求1.2
在進行3.1的操作后,問題得到了部分解決.余下的問題在于需求1.2沒有得到實現(xiàn)和解決.
首先是,如何實現(xiàn)從列表中打開或新建的,替換原來的標簽頁,在來回切換后不會回到原來的標簽頁.只需在app.js中注冊改變標簽頁參數(shù)的方法:
// 變更指定路由的參數(shù)
changeTagParams (state, route) {
let routeOldIndex = state.tagNavList.findIndex(m => routeEqual(m, route))
if (routeOldIndex !== -1) {
let routeOld = state.tagNavList[routeOldIndex]
routeOld.params = route.params
state.tagNavList.splice(routeOldIndex, 1, routeOld)
setTagNavListInLocalstorage([...state.tagNavList])
}
},
然后在main.vue中對$route的監(jiān)控最后引用即可.
watch: {
// 檢測route的變化
$route (newRoute) {
const { name, query, params, meta } = newRoute
this.addTag({
route: { name, query, params, meta },
type: 'push'
})
this.setBreadCrumb(newRoute)
this.setTagNavList(getNewTagList(this.tagNavList, newRoute))
this.$refs.sideMenu.updateOpenName(newRoute.name)
// 增加路由參數(shù)變更環(huán)節(jié)
this.changeTagParams(newRoute)
}
},
其次,如果出現(xiàn)像保存并新增,或者從未保存到已保存,這兩種情況來回切換后不會回到原來的情況.
保存并新增,關鍵是"新增"效果:
// 清空數(shù)據(jù),該方法在保存后調用
clearData () {
//該部分是用來清除當前route的參數(shù)
this.$router.push({
params: Object.assign(this.$route.params, { id: undefined })
})
//這部分代碼是用來清空當前頁面內容,每個模塊都不盡相同,不必模仿
this.mOtherExpense = JSON.parse(JSON.stringify(this.mOtherExpenseInitial))
this.tableData = [{}]
this.loadCode()
this.mOtherExpense.openingDate = new Date()
},
從未保存到已保存,關鍵同樣是如何讓route記住新的id(或其他參數(shù)):
// 設置路由id,該方法在第一次保存后調用
setData (id) {
//這里的id是保存后從后臺傳來的新id
this.$router.push({
params: Object.assign(this.$route.params, { id })
})
}
文中已將本人常用的iviewrouter控制方式提出,或有未涉及者,根據(jù)以下了解大概也可解決:
app.js中的state.tagNavList是標簽頁中顯示的標簽集合;如果要改變一些內容,main.vue中對$route的監(jiān)控是事件發(fā)起的開端,可考慮從這里修改;
以上就是小猿圈web前端講師對于基于iview的router常用控制方式的介紹,記住一定要練習,多學多看多練這才是學習一門新技術好的開始,如果沒有系統(tǒng)的視頻可以觀看小猿圈,里面有更完善更全的視頻。
面是測試html5重力感應的demo
http://bbs.qietu.com/html/zhongli/
http://www.qietu.com/html/f2/qqqianbao/
demo2是切圖網為騰訊網提供的web前端技術支持的項目,采用的就是html5的重力感應。
重力感應主要用到兩種事件:
1 orientationchange
這個事件在屏幕發(fā)生翻轉時觸發(fā)
window.orientation可獲得設備的方向,一共有三個值0:豎直, 90:右旋, -90:左旋
2 deviceorientation 和 MozOrientation(firefox專用)
deviceorientation事件可獲得三個值alpha,beta,gamma,分別代表繞Z軸的旋轉角度(0~360),繞X軸的旋轉角度(-180~180),繞Y軸的旋轉角度(-90~90)
MozOrientation事件中可獲得三個值z,x,y,分別代表垂直加速度,左右的傾斜角度,前后的傾斜角度(取值范圍:-1~1)
坐標系見下圖
下面是示例游戲用到重力感應的代碼:
window.onorientationchange = function(e){
game.hideNavBar(); //屏幕翻轉時隱藏地址欄
if(game.stage) game.stage.updatePosition(); //更新舞臺位置
};
window.ondeviceorientation = function(e)
{
var ang;
var o = window.orientation; //獲取設備方向
if(o == 90){
ang = e.beta; //設備橫向1
}
else if(o == -90){
ang = -e.beta; //設備橫向2
}
else if(o == 0){
ang = e.gamma; //設備縱向
}
if(ang > 5)
{
keyState[Q.KEY.RIGHT] = true;
}
else if(ang < -5)
{
keyState[Q.KEY.LEFT] = true;
}
else
{
keyState[Q.KEY.RIGHT] = false;
keyState[Q.KEY.LEFT] = false;
}
}
無附件,源碼面前,了無秘密,作為web前端工程師,我們需要具備查看源碼的能力。
原文:http://bbs.qietu.com/forum.php?mod=viewthread&tid=15036
*請認真填寫需求信息,我們會在24小時內與您取得聯(lián)系。