Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
## 回答1:中文后臺管理系統模板是一種為網站或應用程序開發者提供的可重復使用的界面模板。它以中文為主要語言,并具有專為后臺管理任務設計的特點和功能。該模板采用HTML語言編寫,可通過復制和粘貼來使用。它通常包含了常見的后臺管理功能,如用戶管理、權限管理、數據管理等。模板的結構和布局已經預先設計好,使開發者可以快速搭建出界面整潔、功能完善的后臺管理系統。中文后臺管理系統模板通常具有以下特點:1. 響應式設計:模板能夠適應各種屏幕尺寸,包括桌面、平板和手機。這使得用戶無論使用何種設備訪問后臺管理系統扁平化后臺管理系統,都能獲得良好的用戶體驗。2. 豐富的組件和布局:模板提供了豐富的界面組件和布局選項,如導航欄、表格、圖表等,使開發者能夠根據實際需求快速構建頁面。3. 可定制性強:開發者可以根據自身需求對模板進行定制,包括更改顏色、字體、布局等。這樣可以讓界面更符合項目的品牌和風格。4. 支持多語言:由于是中文模板,所以它自然支持中文。但是,它也可以支持其他語言,如英語、西班牙語等,以滿足全球范圍的使用需求。總之,中文后臺管理系統模板是一個方便快捷的工具,能夠幫助開發者節省時間和精力,從而更專注地進行后臺管理相關的開發工作。
### 回答2:中文后臺管理系統模板html是一種用于構建中文界面的后臺管理系統的HTML模板。它提供了一系列預定義的頁面布局和組件,方便開發人員快速構建功能強大、易于使用的后臺管理系統。中文后臺管理系統模板html通常包含以下主要組件和功能:1. 導航菜單:提供多級菜單,用于導航不同的功能頁面。菜單通常以樹形結構呈現,可以自由添加、刪除和編輯菜單項。2. 歡迎頁:作為系統登錄后的默認頁面,展示系統的基本信息和功能模塊的快速訪問入口。3. 數據表格:用于展示和編輯數據的表格組件,支持數據分頁、排序、篩選和批量操作等功能。4. 表單界面:提供各種表單元素,如輸入框、下拉框、復選框等,用于用戶輸入和提交數據。5. 圖表和統計:支持各種數據可視化圖表和統計報表,幫助管理員了解系統的運行狀況和數據分析。6. 權限管理:提供用戶和角色管理功能,支持不同用戶角色的權限設置和訪問控制。7. 主題和樣式:支持自定義的主題和樣式,方便根據實際需求進行界面風格的調整。8. 響應式布局:適應不同設備和屏幕尺寸,保證后臺管理系統在桌面和移動設備上的正常使用。通過使用中文后臺管理系統模板html,開發人員可以省去從零開始構建后臺管理系統的繁瑣工作,提高開發效率和用戶體驗。
同時,模板也提供了豐富的功能和組件,滿足不同后臺管理系統的需求,并支持自定義擴展。 ### 回答3:中文后臺管理系統模板HTML是一種用于構建中文后臺管理系統界面的模板。這種模板通常由HTML、CSS和等前端技術組成,旨在提供一套可復用的界面元素和樣式,使用戶可以快速、方便地搭建自己的管理系統。中文后臺管理系統模板HTML通常包括多個頁面扁平化后臺管理系統,如登錄頁面、主頁、用戶管理頁面、數據分析頁面等。每個頁面都有相應的HTML結構和樣式,以及與后臺服務器進行數據交互的代碼。這些頁面之間通過導航菜單或鏈接相互跳轉,以實現不同功能的管理和操作。在中文后臺管理系統模板HTML中,常見的界面元素包括頂部導航欄、側邊菜單欄、數據表格、表單、圖表等。這些元素通過CSS進行布局和樣式設計,以及通過實現一些交互效果,如表單驗證、數據篩選、圖表展示等。中文后臺管理系統模板HTML的優點是可定制性高,用戶可以根據自己的需求進行靈活的修改和擴展,以滿足不同的管理系統需求。它還可以提高開發效率,節省開發成本,因為用戶無需從零開始設計和開發界面,只需要根據模板的結構進行相應修改即可。總之,中文后臺管理系統模板HTML是一種便捷、高效的搭建中文后臺管理系統界面的工具,可以幫助用戶快速構建出美觀、功能完善的管理系統。
一個網站都有自己的導航菜單,如:頭部導航菜單,底部導航菜單,側邊欄導航菜單,wordpress網站也不例外。那么,在wordpress網站主題模板開發中,我們怎樣給wordpress網站添加前臺的導航菜單呢?嗯,據我多年的開發經驗發現,wordpress為wordpress主題開發,主要提供了三種導航菜單的創建方式,這三種方式會創建不一樣的導航功能。今天,我們就來看看第一種wordpress網站創建導航菜單的方式——基于page頁面的導航菜單。這里,我們會用到wordpress提供的函數——wp_list_pages(),這是一個wordpress頁面列表的函數。
我們先來看一下這個wordpress函數——wp_list_pages(),看看它的結構。
wp_list_pages($defaults);
從上面的代碼中,我們可以看到,wp_list_pages()函數只有一個參數,這個參數有兩種類型,可以是字符串類型,也可以是數組類型。這個我們在下面的實例中會做相應的介紹。為了方便了解這個參數的值,我們這里以數組的形式來解說一下這個參數。
參數介紹:
$defaults =array('depth' =>0, //0:顯示所有頁面和子頁面,按層級顯示;//1:只顯示頂級頁面;//2:顯示2級頁面;//-1:顯示所有頁面和子頁面,不按層級顯示;
'show_date'=>'', //是否顯示創建日期
'date_format'=> get_option('date_format'),//日期格式
'child_of'=>0, //指定父頁面ID號,顯示這個父頁面下的子頁面;0表示顯示所有子頁面;
'exclude'=>'', //排除哪些頁面
'include'=>'', //包含哪些頁面
'title_li'=>'Pages', //是否顯示頁面列表的標題,如果不顯示,設為空;這里設置標題為“Pages”
'echo'=>1, //是否打印到前臺頁面顯示出來。1表示顯示,0表示不顯示,而是只獲取值。
'authors'=>'', //指定特定作者創建的頁面
'link_before'=> '', //鏈接<a>前的內容'link_after'=>'', //鏈接<a>后的內容
'exclude_tree'=>'', //排除父級/子級樹
'sort_column'=>'menu_order', //排序方式,menu_order按后臺設置;post_date按發布時間,post_modified按修改時間;
'sort_order' => 'DESC', //排序順序,ASC順序,DESC是倒序);
可以看到,這個wp_list_pages()函數的參數值有很多,在我們wordpress主題模板開發的實際操作中,一般只會使用其中的幾個。
下面,我們通過案例來介紹wp_list_pages()函數是如何生成基于page頁面的導航菜單的。我們先來看一下,wordpress網站后臺都創建了哪些page單頁面,如下圖:
從上圖中,我們可以看到,這個wordpress網站后臺有6個頁面,其中,“投稿”是“子頁面1”和“子頁面2”的父級頁面。
案例1:我們在wordpress網站模板的頭部添加如下代碼:
$menu = array( 'depth' =>0, 'title_li'=>'頁面導航菜單', 'echo'=>1, );wp_list_pages($menu);
我們再到wordpress網站的前臺頁面看一下效果,如下圖:
我們可以看到,頁面導航展示了出來,子頁面按層級展示——縮進2格。
案例2:我們來修改一個參數代碼,標題設置為空,添加一個排序參數,并修改一下層級參數值,代碼如下:
$menu = array( 'depth' =>1, 'title_li'=>'頁面導航菜單', 'echo'=>1, 'sort_order' => 'DESC','sort_column'=>'menu_order',);wp_list_pages($menu);
這時,我們再來看看wordpress網站前臺頁面的效果,如下圖:
?我們可以看到,導航菜單的標題不見了,而且層級沒有了,排序也發生了變化,按頁面名稱的倒序來進行排列。wp_list_pages()的參數很多,這里不做一一演示,都很簡單。
案例3:wp_list_pages()函數的參數用字符串類型。
我人在開頭說過,wp_list_pages()函數的參數有2種類型,可以是字符串類型,也可以是數組類型。數組類型我們在前2個案例中已經使用過了。這里,我們再來以字符串類型來做一次介紹。
這里我們拿案例的代碼來演示,把數組類型的參數換成字符串的類型,代碼如下:
wp_list_pages("depth=1&title=&echo=1&sort_order=DESC&sort_column=menu_order");
上面的代碼中,我們用到了一個連接符&這個特殊符號,它是用來連接多個參數。中間的=這個符號,就不用解釋了,是等于號。通過這句代碼,我們同樣達到案例2的效果。
如果想讓這個基于page頁面的導航菜單能在頂部橫排顯示,可以修改wordpress網站模板的CSS文件的代碼,修改它的樣式,就可以了。這里就不多說了。
這節課就介紹到這里,以上就是我的觀點,如有不同觀點,歡迎發表評論。同時,歡迎【點贊、分享、收藏】和【關注】我。
SM(Finite State Machines) 有限狀態機,也叫有限狀態自動機,是為研究有限內存的計算過程和某些語言類而抽象出的一種計算模型,它擁有有限個數量的狀態,每個狀態可以遷移到零個或多個狀態,輸入字串決定執行哪個狀態的遷移。
代碼編譯器在工作時就需要通過詞法分析、語法分析、語義分析來得到 AST(Abtract Syntaxt Tree) 抽象語法樹。需要先詞法分析拿到的所有 token 流,接著通過語法分析將 token 流進行文法校驗生成語法解析樹,這個過程一般有兩種:
我們在前端工作中經常用到的:babel、typescript、eslint、postcss、prettier、uniapp、htmlparse、代碼編輯器的語法高亮...這些其實都是基于 AST 抽象語法樹來實現的,而為了得到 AST 我們需要先進行分詞,而分詞一個比較好的方式就是通過有限狀態機來實現。
代碼的本質就是字符串,分詞就是把代碼字符串變成一個個最小單元到不能再拆分的單詞,也叫 token(注意不是咱們平時用到的登錄態 token),分詞器的英文 tokenizer。代碼其實跟我們一篇英文文章、一首中文古詩、一個數學運算...都是一樣的,我們一樣可以用分詞技術來拆分這些元素。
為了理解有限狀態機到底是怎么工作的,我們先來實現一個簡單的減法運算分詞。要求用狀態機把 500-250=250 這個減法運算分詞成一個數組,首先定義一共有2種狀態:number-數字、operator-運算符,每一個最小的 token 只能是這兩個當中的一個,代碼如下
// 500-250=250
// [
// { type: 'number', value: '500' },
// { type: 'operator', value: '-' },
// { type: 'number', value: '250' },
// { type: 'operator', value: '=' },
// { type: 'number', value: '250' }
// ]
function mathTokenizer(text) {
// 匹配數字正則
const numberReg = /[0-9]/
// 匹配運算符正則
const operatorReg = /[-=]/
// 存儲所有讀取到的 token 數組
let tokens = []
// 當前正在讀取的 token 信息
let currentToken = {}
// 初始狀態
function init(e) {
if (numberReg.test(e)) {
currentToken = { type: 'number', value: e }
return onNumber
} else if (operatorReg.test(e)) {
currentToken = { type: 'operator', value: e }
return onOperator
}
}
// 讀取到數字
function onNumber(e) {
if (numberReg.test(e)) {
currentToken.value += e
return onNumber
}
if (operatorReg.test(e)) {
pushToken(currentToken)
currentToken = { type: 'operator', value: e }
return onOperator
}
}
// 讀取到運算符
function onOperator(e) {
if (numberReg.test(e)) {
pushToken(currentToken)
currentToken = { type: 'number', value: e }
return onNumber
}
if (operatorReg.test(e)) {
pushToken(currentToken)
currentToken = { type: 'operator', value: e }
return onOperator
}
}
// 每次讀取到完整的一個 token 后存入到數組中
function pushToken(token) {
tokens.push(token)
currentToken = {}
}
// 遍歷讀取數組
function parse(str) {
const len = str.length
let stateMachine = init
for (let i = 0; i < len; i++) {
const char = str[i]
stateMachine = stateMachine(char)
// 最后一個字符匹配完了要自己 pushToken
if (i === len - 1) {
pushToken(currentToken)
}
}
return tokens
}
return parse(text)
}
const arr = mathTokenizer('500-250=250')
console.log(arr)
簡版的 html 解析器
利用狀態機來生成 token 流,為了方便理解以下示例不考慮標簽屬性節點、自閉合標簽和一些異常情況。
我們先定義5個狀態:標簽開始、結束標簽開始、標簽名、標簽結束、文本,每次讀取到的內容會在這5個狀態之間切換,每次讀取時只要不是標簽開始、結束標簽開始、標簽名、標簽結束這4個狀態的我們都當成文本來處理。
實際上我們只需要存儲:開始標簽、文本、結束標簽這3個狀態,所以定義的節點 type 分別為:startTag、text、endTag。你要按前面定義的5個狀態來儲存其實也是可以的,在下面生成 AST 直接忽略掉我們不需要的標簽開始、標簽結束這些狀態信息就行了,只不過這里我們直接在分詞這一步提前就給過濾了。
這里我們可以把狀態機理解成一個函數,每遍歷到一個字符我們都將這個字符傳到函數中,而函數中可以根據這個字符來判斷下一個狀態是什么,再返回出去下一個狀態函數就行了。
function htmlTokenizer(str){
// 標簽開始
const tagStartReg = /</
// 結束標簽開始
const closeTagReg = /\//
// 標簽結束
const tagEndReg = />/
// 標簽名
const tagNameReg = /[a-zA-Z]/
let tokens = []
let currentToken = {}
// 初始狀態
function init(e) {
if (tagStartReg.test(e)) {
currentToken = { type: 'startTag', tagName: '' }
return init
}
if (closeTagReg.test(e)) {
currentToken = { type: 'endTag', tagName: '' }
return onTagName
}
if (tagNameReg.test(e)) {
currentToken.tagName += e
return onTagName
}
// 不是上面3個狀態的都當成文本節點處理
currentToken = { type: 'text', text: e }
return onText
}
// 讀取到標簽名
function onTagName(e) {
if (tagEndReg.test(e)) {
pushToken(currentToken)
return init
} else {
currentToken.tagName = (currentToken.tagName || '') + e
return onTagName
}
}
// 讀取到文本
function onText(e) {
if (tagStartReg.test(e)) {
pushToken(currentToken)
currentToken = { type: 'startTag', tagName: '' }
return init
} else {
currentToken.text = (currentToken.text || '') + e
return onText
}
}
// 每次讀取到完整的一個 token 后存入到數組中
function pushToken(e) {
tokens.push(e)
currentToken = {}
}
// 遍歷讀取數組
function parse(chars){
let stateMachine = init
for (const char of chars) {
stateMachine = stateMachine(char)
}
return tokens
}
return parse(str)
}
const tokenList = htmlTokenizer('<div>靜夜思<p>鋤禾日當午</p>周小黑<p>粒粒皆辛苦</p>公元一七八八年</div>')
console.log(tokenList)
這一步主要就怎么能把分詞得到的數組轉換成樹形 tree 數據結構,日常開發中我們 array 轉 tree 一般都是需要根據父親 id 之類的來實現遍歷生成,但是這里咱拿到的數組是沒有這個父 id 的,那要怎么實現呢?
先觀察數據結構,雖然是一個數組,但是這個數組其實是個類似中心對稱結構的,我們暫時先忽略掉數組里的 type 為 text 的文本內容(因為這個其實我們是不能把它當成一個父節點的,它只能是某個標簽的子節點),過濾掉文本后數組第1個元素和最后1個元素正好是1對,第2個元素和倒數第2個元素又是1對,我們要實現的就是把內層獲取到的一對對標簽不斷掛載到它前面一對簽的 children 屬性上來實現 tree 結構。
那我們可以從數組第一項目開始遍歷,然后用一個數組來模擬 stack 棧存每次遍歷到的標簽信息(棧的特點是先進后出,類似我們往一個桶里放東西,放在最上面的可以最先拿出來,規定數組只能使用 push 和 pop 就能模擬棧了)。
當遇到開始標簽的時候就說明遇到一個新的標簽了,這時就往棧里 push 進去,當遇到結束標簽時就說明當前這個標簽的所有信息都已經讀取處理完了,那我們就可以將它從棧里彈出來,然后現在棧里最上面的一個元素其實就是當前彈出來的父標簽了,直接掛載到 children 上就行了。整個過程其實主要就是理解下面2點:
function htmlAst(tokenList) {
let stack = []
for (let i = 0; i < tokenList.length; i++) {
const node = tokenList[i]
// 開始標簽:入棧
if (node.type === 'startTag'){
stack.push(node)
}
// 結束標簽:出棧
if (node.type === 'endTag') {
const currentNode = stack.pop()
const parent = stack[stack.length - 1]
if (parent) {
if (!parent.children) parent.children = []
parent.children.push(currentNode)
} else {
const root = { type: 'document', children: [currentNode] }
return root
}
}
// 文本:加到父標簽的 children 上
if (node.type === 'text') {
const parent = stack[stack.length - 1]
if (!parent.children) parent.children = []
parent.children.push(node)
}
}
}
然后就能拿到我們需要的 AST 語法樹了,結構如下:
{
"type": "document",
"children": [
{
"type": "startTag",
"tagName": "div",
"children": [
{
"type": "text",
"text": "靜夜思"
},
{
"type": "startTag",
"tagName": "p",
"children": [
{
"type": "text",
"text": "鋤禾日當午"
}
]
},
{
"type": "text",
"text": "周小黑"
},
{
"type": "startTag",
"tagName": "p",
"children": [
{
"type": "text",
"text": "粒粒皆辛苦"
}
]
},
{
"type": "text",
"text": "公元一七八八年"
}
]
}
]
}
理解了狀態機就如給你按上了一雙翅膀,不管給你任何一段字符任容,都可以通過狀態機來拆分成我們想要的結構,理解了上面這些再去看 vue 里的模板編譯,你就能知道它到底是怎么加進去那些語法糖的了。還比如小程序中的富文本解析,特定平臺的小程序實際上是不能識別瀏覽器里的 html 的,那我們就需要先將 html 通過狀態機轉成 AST,然后再按照小程序的語法來進行特定的轉換。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。