一套程式碼小程式&Web&Native執行的探索05——snabbdom
參考:
https://github.com/fastCreator/MVVM(極度參考,十分感謝該作者,直接看Vue會比較吃力的,但是看完這個作者的程式碼便會輕易很多,可惜這個作者沒有對應部落格說明,不然就爽了)
https://www.tangshuang.net/3756.html
https://www.cnblogs.com/kidney/p/8018226.html
http://www.cnblogs.com/kidney/p/6052935.html
https://github.com/livoras/blog/issues/13
根據最近的學習,離我們最終的目標還有一段距離,但是對於Vue實現原理卻慢慢有了體系化的認識,相信本系列結束後,如果能完成我們跨端程式碼,哪怕是demo的實現,都會對後續瞭解Vue或者React這裡原始碼提供深遠的幫助,平時工作較忙,這次剛好碰到假期,雖然會耽擱一些時間,我們試試這段時間運氣可好,能不能在這個階段取得不錯的進展,好了我們繼續完成今天的學習吧
到目前的地步,其中一些程式碼比較散亂,沒有辦法粘貼出來做講解了,我這邊儘量寫註釋,這裡文章記錄的主要目的還是幫助自己記錄思路
昨天,我們完成了最簡單的模板到DOM的實現,以及執行setData時候頁面重新渲染工作,只不過比較粗暴還沒有引入snabbdom進行了重新渲染,今天我們來完成其中的事件繫結部分程式碼
這裡我們先不去管迴圈標籤這些的解析,先完成事件繫結部分程式碼,這裡如果只是想實現click繫結便直接在此處繫結事件即可:
1 class Element { 2 constructor(tagName, props, children, vm) { 3 this.tagName = tagName; 4 this.props = props; 5 this.children = children || []; 6 this.vm = vm.vm; 7 } 8 render() { 9 //拿著根節點往下面擼 10 let el = document.createElement(this.tagName); 11 let props = this.props.props; 12 let scope = this; 13 14 let events = this.props.on; 15 16 for(let name in props) { 17 el.setAttribute(name, props[name]); 18 } 19 20 for(name in events) { 21 let type = Object.keys(this.props.on); 22 type = type[0]; 23 el.addEventListener(type, function (e) { 24 scope.vm.$options.methods[scope.props.on[type]] && scope.vm.$options.methods[scope.props.on[type]].call(scope.vm, e); 25 }) 26 } 27 28 let children = this.children; 29 30 for(let i = 0, l = children.length; i < l; i++) { 31 let child = children[i]; 32 let childEl; 33 if(child instanceof Element) { 34 //遞迴呼叫 35 childEl = child.render(); 36 } else { 37 childEl = document.createTextNode(child); 38 } 39 el.append(childEl); 40 } 41 return el; 42 } 43 }
顯然,這個不是我們要的最終程式碼,事實上,事件如何繫結dom如何比較差異渲染,我們這塊不需要太多關係,我們只需要引入snabbdom即可,這裡便來一起了解之
snabbdom
前面我們對snabbdom做了初步介紹,暫時看來MVVM框架就我這邊學習的感覺有以下幾個難點:
① 第一步的模板解析,這塊很容易出錯,但如果有志氣jQuery原始碼的功底就會比較輕易
② 虛擬DOM這塊,要對比兩次dom樹的差異再選擇如何做
只要突破這兩點,其他的就會相對簡單一些,而這兩塊最難也最容易出錯的工作,我們全部引用了第三方庫HTMLParser和snabbdom,所以我們都碰上了好時代啊......
我們很容易將一個dom結構用js物件來抽象,比如我們之前做的班次列表中的列表排序:
這裡出發的因子就有出發時間、耗時、價格,這裡表示下就是:
1 let trainData = { 2 sortKet: 'time', //耗時,價格,發車時間等等方式排序 3 sortType: 1, //1升序,2倒敘 4 oData: [], //伺服器給過來的原生資料 5 data: [], //當前篩選條件下的資料 6 }
這個物件有點缺陷就是不能與頁面對映起來,我們之前的做法就算對映起來了,也只會跟一個跟節點做繫結關係,一旦資料發生變化便全部重新渲染,這個還是小問題,比較複雜的問題是半年後篩選條件增加,這個頁面的程式碼可能會變得相當難維護,其中最難的點可能就是頁面中的dom關係維護,和事件維護
而我們想要的就是資料改變了,DOM自己就發生變化,並且以高效的方式發生變化,這個就是我們snabbdom做的工作了,而之前我們用一段程式碼說明過這個問題:
var element = { tagName: 'ul', // 節點標籤名 props: { // DOM的屬性,用一個物件儲存鍵值對 id: 'list' }, children: [ // 該節點的子節點 {tagName: 'li', props: {class: 'item'}, children: ["Item 1"]}, {tagName: 'li', props: {class: 'item'}, children: ["Item 2"]}, {tagName: 'li', props: {class: 'item'}, children: ["Item 3"]}, ] }
1 <ul id='list'> 2 <li class='item'>Item 1</li> 3 <li class='item'>Item 2</li> 4 <li class='item'>Item 3</li> 5 </ul>
真實的虛擬DOM會翻譯為這樣:
class Element { constructor(tagName, props, children) { this.tagName = tagName; this.props = props; this.children = children; } } function el(tagName, props, children) { return new Element(tagName, props, children) } el('ul', {id: 'list'}, [ el('li', {class: 'item'}, ['Item 1']), el('li', {class: 'item'}, ['Item 2']), el('li', {class: 'item'}, ['Item 3']) ])
這裡很快就能封裝一個可執行的程式碼出來:
<!doctype html> <html> <head> <title>起步</title> </head> <body> <script type="text/javascript"> //***虛擬dom部分程式碼,後續會換成snabdom class Element { constructor(tagName, props, children) { this.tagName = tagName; this.props = props; this.children = children; } render() { //拿著根節點往下面擼 let root = document.createElement(this.tagName); let props = this.props; for(let name in props) { root.setAttribute(name, props[name]); } let children = this.children; for(let i = 0, l = children.length; i < l; i++) { let child = children[i]; let childEl; if(child instanceof Element) { //遞迴呼叫 childEl = child.render(); } else { childEl = document.createTextNode(child); } root.append(childEl); } this.rootNode = root; return root; } } function el(tagName, props, children) { return new Element(tagName, props, children) } let vnode = el('ul', {id: 'list'}, [ el('li', {class: 'item'}, ['Item 1']), el('li', {class: 'item'}, ['Item 2']), el('li', {class: 'item'}, ['Item 3']) ]) let root = vnode.render(); document.body.appendChild(root); </script> </body> </html>
我們今天要做的事情,便是把這段程式碼寫的更加完善一點,就要進入第二步,比較兩顆虛擬樹的差異了,而這塊也是snabbdom的核心,當然也比較有難度啦
PS:這裡借鑑:https://github.com/livoras/blog/issues/13
實際程式碼中,會對兩棵樹進行深度優先遍歷,這樣會給每個節點一個唯一的標誌:
在深度優先遍歷的時候,每到一個節點便與新的樹進行對比,如果有差異就記錄到一個物件中:
1 //遍歷子樹,用來做遞迴的 2 function diffChildren(oldNodeChildren, newNodeChildren, index, patches) { 3 4 let leftNode = null; 5 let curNodeIndex = index; 6 7 for(let i = 0, l = oldNodeChildren.length; i < l; i++) { 8 let child = oldNodeChildren[i]; 9 let newChild = newNodeChildren[i]; 10 11 //計算節點的標識 12 curNodeIndex = (leftNode && leftNode.count) ? curNodeIndex + leftNode.count + 1 : curNodeIndex + 1; 13 dfsWalk(child, newChild) 14 leftNode = child; 15 } 16 } 17 18 //對兩棵樹進行深度優先遍歷,找出差異 19 function dfsWalk(oldNode, newNode, index, patches) { 20 //將兩棵樹的不同記錄之 21 patches[index] = []; 22 diffChildren(oldNode.children, newNode.children, index, patches); 23 } 24 25 //對比兩棵樹的差異 26 function diff(oldTree, newTree) { 27 //當前節點標誌 28 let index = 0; 29 //記錄每個節點的差異 30 let patches = {}; 31 //深度優先遍歷 32 return patches; 33 }
patches[0] = [{difference}, {difference}, ...] // 用陣列儲存新舊節點的不同
這裡已經做好了工具流程遍歷節點得出差異,而我們的差異有:
① 替換原來的節點,例如把div換成section
② 移動、刪除、新增子節點,例如把p與ul順序替換
③ 這個比較簡單,修改節點屬性
④ 這個也比較簡單,修改文字內容
這裡給這幾種型別的定義:
let REPLACE = 0 let REORDER = 1 let PROPS = 2 let TEXT = 3
節點替換首先判斷tagname是否一致即可:
patches[0] = [{ type: REPALCE, node: newNode // el('section', props, children) }]
如果給div新增屬性,便記錄之:
patches[0] = [{ type: REPALCE, node: newNode // el('section', props, children) }, { type: PROPS, props: { id: "container" } }]
如果是文字節點便記錄之:
patches[2] = [{ type: TEXT, content: "Virtual DOM2" }]
以上都比較常規,不會做太大改變,情況比較多的是REODER(Reorder重新排列),比如將這裡div的子節點順序變成了div-p-ul,這個該如何對比,其實這個情況可能會直接被替換掉,這樣DOM開銷太大,這裡牽扯到了列表對比演算法,有點小複雜:
假如現在對英文字母進行排序,久的順序:
a b c d e f g h i
然後對節點進行了一系列的操作,新增j節點,刪除e節點,移動h節點,於是有了:
a b c h d f g i j
知道了新舊順序,現在需要我們寫一個演算法計算最小插入、刪除操作(移動是刪除+插入),這塊具體我們不深入,有興趣移步至,這裡程式碼,我們最終形成的結果是:
patches[0] = [{
type: REORDER,
moves: [{remove or insert}, {remove or insert}, ...]
}]
於是我們將這段尋找差異的程式碼放入前面的遍歷程式碼:
function patch (node, patches) { var walker = {index: 0} dfsWalk(node, walker, patches) } function dfsWalk (node, walker, patches) { var currentPatches = patches[walker.index] // 從patches拿出當前節點的差異 var len = node.childNodes ? node.childNodes.length : 0 for (var i = 0; i < len; i++) { // 深度遍歷子節點 var child = node.childNodes[i] walker.index++ dfsWalk(child, walker, patches) } if (currentPatches) { applyPatches(node, currentPatches) // 對當前節點進行DOM操作 } } function applyPatches (node, currentPatches) { currentPatches.forEach(function (currentPatch) { switch (currentPatch.type) { case REPLACE: node.parentNode.replaceChild(currentPatch.node.render(), node) break case REORDER: reorderChildren(node, currentPatch.moves) break case PROPS: setProps(node, currentPatch.props) break case TEXT: node.textContent = currentPatch.content break default: throw new Error('Unknown patch type ' + currentPatch.type) } }) }
這個就是我們snabbdom中重要的patch.js的實現,而Virtual DOM演算法主要就是:① 虛擬DOM element的定義
② 差異的定義與實現
③ 將差異部分程式碼補足形成新樹的patch部分
// 1. 構建虛擬DOM var tree = el('div', {'id': 'container'}, [ el('h1', {style: 'color: blue'}, ['simple virtal dom']), el('p', ['Hello, virtual-dom']), el('ul', [el('li')]) ]) // 2. 通過虛擬DOM構建真正的DOM var root = tree.render() document.body.appendChild(root) // 3. 生成新的虛擬DOM var newTree = el('div', {'id': 'container'}, [ el('h1', {style: 'color: red'}, ['simple virtal dom']), el('p', ['Hello, virtual-dom']), el('ul', [el('li'), el('li')]) ]) // 4. 比較兩棵虛擬DOM樹的不同 var patches = diff(tree, newTree) // 5. 在真正的DOM元素上應用變更 patch(root, patches)
有了以上知識,我們現在來開始使用snabbdom,相比會得心應手
應用snabbdom
var snabbdom = require("snabbdom"); var patch = snabbdom.init([ // 初始化補丁功能與選定的模組 require("snabbdom/modules/class").default, // 使切換class變得容易 require("snabbdom/modules/props").default, // 用於設定DOM元素的屬性(注意區分props,attrs具體看snabbdom文件) require("snabbdom/modules/style").default, // 處理元素的style,支援動畫 require("snabbdom/modules/eventlisteners").default, // 事件監聽器 ]); //h是一個生成vnode的包裝函式,factory模式?對生成vnode更精細的包裝就是使用jsx //在工程裡,我們通常使用webpack或者browserify對jsx編譯 var h = require("snabbdom/h").default; // 用於建立vnode,VUE中render(createElement)的原形 var container = document.getElementById("container"); var vnode = h("div#container.two.classes", {on: {click: someFn}}, [ h("span", {style: {fontWeight: "bold"}}, "This is bold"), " and this is just normal text", h("a", {props: {href: "/foo"}}, "I\"ll take you places!") ]); // 第一次打補丁,用於渲染到頁面,內部會建立關聯關係,減少了建立oldvnode過程 patch(container, vnode); //建立新節點 var newVnode = h("div#container.two.classes", {on: {click: anotherEventHandler}}, [ h("span", {style: {fontWeight: "normal", fontStyle: "italic"}}, "This is now italic type"), " and this is still just normal text", h("a", {props: {href: "/bar"}}, "I\"ll take you places!") ]); //第二次比較,上一次vnode比較,打補丁到頁面 //VUE的patch在nextTick中,開啟非同步佇列,刪除了不必要的patch //nextTick非同步佇列解析,下面文章中會詳解 patch(vnode, newVnode); // Snabbdom efficiently updates the old view to the new state
這裡可以看到,我們傳入h的要求是什麼樣的格式,依次有什麼屬性,這裡還是來做一個demo:
1 <div id="container"> 2 </div> 3 4 <script type="module"> 5 "use strict"; 6 import { patch, h, VNode } from './libs/vnode.js' 7 var container = document.getElementById("container"); 8 function someFn(){ console.log(1)} 9 function anotherEventHandler(){ console.log(2)} 10 11 var oldVnode = h("div", {on: {click: someFn}}, [ 12 h("span", {style: {fontWeight: "bold"}}, "This is bold"), 13 " and this is just normal text", 14 h("a", {props: {href: "/foo"}}, "I\"ll take you places!") 15 ]); 16 17 // 第一次打補丁,用於渲染到頁面,內部會建立關聯關係,減少了建立oldvnode過程 18 let diff = patch(container, oldVnode); 19 //建立新節點 20 var newVnode = h("div", {on: {click: anotherEventHandler}}, [ 21 h("span", {style: {fontWeight: "normal", fontStyle: "italic"}}, "This is now italic type"), 22 " and this is still just normal text", 23 h("a", {props: {href: "/bar"}}, "I\"ll take you places!") 24 ]); 25 //第二次比較,上一次vnode比較,打補丁到頁面 26 //VUE的patch在nextTick中,開啟非同步佇列,刪除了不必要的patch 27 //nextTick非同步佇列解析,下面文章中會詳解 28 patch(oldVnode, newVnode); // Snabbdom efficiently updates the old view to the new state 29 function test() { 30 return { 31 oldVnode,newVnode,container,diff 32 } 33 } 34 </script>
所以我們現在工作變得相對簡單起來就是根據HTML模板封裝虛擬DOM結構即可,如果不是我們其中存在指令系統甚至可以不用HTMLParser,所以我們改下之前的程式碼,將我們自己實現的醜陋vnode變成snabbdom,這裡詳情還是看github:https://github.com/yexiaochai/wxdemo/tree/master/mvvm。接下來,我們來解決其中的指令
指令系統
這裡所謂的指令用的最多的也就是:
① if
② for
對應到小程式中就是:
<block wx:for="{{[1, 2, 3]}}"> <view> {{index}}: </view> <view> {{item}} </view> </block>
<block wx:if="{{true}}"> <view> view1 </view> <view> view2 </view> </block>
Vue中的語法是:
<ul id="example-1"> <li v-for="item in items"> {{ item.message }} </li> </ul>
<h1 v-if="ok">Yes</h1> <h1 v-else>No</h1>
大同小異,我們來看看如何處理這種程式碼,這裡也開始進入陣列物件的處理,這裡便引入了指令系統,我們這裡單獨說下這塊程式碼
框架裡面的for或者if這種指令程式碼因為要要保證框架性,首先寫的很分散,其次用起來也很繞,就很不好理解,所以這裡需要單獨拎出來說下
之前我們使用的模板一般就是js程式碼,直接被翻譯為了js函式,比如這段程式碼:
<ul> <% for(let key in arr) { %> <li>...</li> <% } %> </ul>
會被大概翻譯為這個樣子:
var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');}; with(obj||{}){ __p+='<ul>\n '; for(let key in arr) { __p+='\n <li>...</li>\n '; } __p+='\n</ul>'; } return __p;
而MVVM類框架執行的是相同的邏輯,只不過程式碼實現上面因為要考慮對映關係就複雜的多了:
<ul> <li m-for="(val, key, index) in arr">索引 {{key + 1}} :{{val}} </li> </ul>
翻譯後基本就是這個程式碼:
with (this) { debugger ;return _h('ul', {}, [_l((arr), function(val, key, index) { return _h('li', { attrs: { "m-for": '(val, key, index) in arr' } }, ["索引 " + _s(key + 1) + " :" + _s(val)]) })]) }
所有的這一切都是為了形成虛擬樹結構,最終要的是這樣的東西
所以指令是其中的工具,一個過程,幫助我們達到目的,為了幫助理解,我們這邊單獨抽一段程式碼出來說明這個問題,這裡再強調一下指令系統在整體流程中的意義是:
我們最終目標是將模板轉換為snabbdom中的vnode,這樣他便能自己渲染,而這裡的過程是
模板 => HTMLParser解析模板 => 框架element物件 => 解析框架element物件中的屬性,這裡包括指令 => 將屬性包含的指令相關資訊同步到element物件上(因為每個標籤都會有element物件)=> 生成用於render的函式(其實就是將element轉換為snabbdom可識別的物件) => 生成snabbdom樹後,呼叫pacth即可完成渲染
所以指令系統在其中的意義便是:解析element中的指令對應的程式碼,方便後續生成render匿名函式罷了,這就是為什麼指令系統的實現包含了兩個方法:
① template2Vnode,這個事實上是將模板中與指令相關的資訊放到element物件上方便後續vnode2render時候使用
② vnode2render,便是將之前存到element中與生成最終函式有關的欄位拿出來拼接成函式字串,呼叫的時候是在mvvm例項物件下,所以可以取到傳入的data以及method
之所以設計的比較複雜是為了讓大家方便新增自定義指令,這裡仍然先上一段簡單的說明性程式碼:
1 <!doctype html> 2 <html> 3 <head> 4 <title>指令系統演示</title> 5 </head> 6 <body> 7 8 <script type="module"> 9 10 //需要處理的模板,我們需要將他轉換為虛擬dom vnode 11 let html = ` 12 <ul> 13 <li m-for="(val, key, index) in arr">索引 {{key + 1}} :{{val}}</li> 14 </ul> 15 ` 16 //這裡我們為了降低學習成本將這段模板再做一次簡化,變成這樣 17 html = '相關推薦
一套程式碼小程式&Web&Native執行的探索02
接上文:一套程式碼小程式&Web&Native執行的探索01,本文都是一些探索性為目的的研究學習,在最終版輸出前,內中的內容可能會有點亂 參考: https://github.com/fastCreator/MVVM https://www.tangshuang.net/3756.htm
一套程式碼小程式&Web&Native執行的探索(1)
前言 之前一直在跟業務方打交道後面研究了下後端,期間還做了一些運營、管理相關工作,哈哈,最近一年工作經歷十分豐富啊,生命在於不斷的嘗試嘛。 當然,不可避免的在前端技術一塊也稍微有點落後,對React&Vue沒有進行過深入一點的研究,這裡得空我們便來一起研究一番(回想起來寫程式碼的日子才是最快樂的
一套程式碼小程式&Web&Native執行的探索03
我們在研究如果小程式在多端執行的時候,基本在前端框架這塊陷入了困境,因為市面上沒有框架可以直接拿來用,而Vue的相識度比較高,而且口碑很好,我們便接著這個機會同步學習Vue也解決我們的問題,我們看看這個系列結束後,會不會離目標進一點,後續如果實現後會重新整理系列文章...... 參考: https:/
一套程式碼小程式&Web&Native執行的探索(2)
接上文:一套程式碼小程式&Web&Native執行的探索01,本文都是一些探索性為目的的研究學習,在最終版輸出前,內中的內容可能會有點亂 參考: https://github.com/fastCreator/MVVM https://www.tangshuang.net/3756.html
一套程式碼小程式&Web&Native執行的探索04——資料更新
參考: https://github.com/fastCreator/MVVM(極度參考,十分感謝該作者,直接看Vue會比較吃力的,但是看完這個作者的程式碼便會輕易很多,可惜這個作者沒有對應部落格說明,不然就爽了) https://www.tangshuang.net/3756.html htt
一套程式碼小程式&Web&Native執行的探索05——snabbdom
參考: https://github.com/fastCreator/MVVM(極度參考,十分感謝該作者,直接看Vue會比較吃力的,但是看完這個作者的程式碼便會輕易很多,可惜這個作者沒有對應部落格說明,不然就爽了) https://www.tangshuang.net/3756.html h
一套程式碼小程式&Web&Native執行的探索07——mpvue簡單調研
前言 最近工作比較忙,加之上個月生了小孩,小情人是各種折騰他爸媽,我們可以使用的獨立時間片不多,雖然這塊研究進展緩慢,但是一直做下去,肯定還是會有一些收穫的 之前我們這個課題研究一直是做獨立的研究,沒有去看已有的解決方案,這個是為了保證一個自己獨立的思維,無論獨立的思維還是人格都是很重要的東西,然獨學
【一套程式碼小程式&Native&Web階段總結篇】可以這樣閱讀Vue原始碼
前言 在實際程式碼過程中我們發現,我們可能又要做H5站又要做小程式同時還要做個APP,這裡會造成很大的資源浪費,如果設定一個規則,讓我們可以先寫H5程式碼,然後將小程式以及APP的業務差異程式碼做掉,豈不快哉?但小程式的web框架並不開源,不然也用不著我們在此費力了,經過研究,小程式web端框架是一套自
uni-app 1.4 釋出,一套程式碼,發行小程式(微信/支付寶/百度)、H5、App多個平臺
在2019新年到來之際,uni-app 1.4版本正式釋出,新增支援百度、支付寶小程式,開放外掛市場,同時注入更多優秀特性,為開發者送上了一份新年大禮! 支援更多小程式平臺 uni-app 1.4 版本新增支援百度、支付寶小程式,從此一次開發,可釋出小程式(微信/支付寶/百度)、H5、App(iOS/An
uni-app 是一個使用 Vue.js 開發跨平臺應用的前端框架,開發者編寫一套程式碼,可編譯到iOS、Android、微信小程式等多個平臺。
uni-app 是一個使用 Vue.js 開發跨平臺應用的前端框架,開發者編寫一套程式碼,可編譯到iOS、Android、微信小程式等多個平臺。 uni-app在跨端數量、擴充套件能力、效能體
React Native 中為IOS和Android設定不同的Style樣式,一套程式碼解決雙端顯示
React Native 開發中,大多數的元件都是IOS和Android通用的,包括大量的功能性程式碼,至少有80%以上的程式碼可以複用,而剩下的一些元件樣式/少量的程式碼會需要區分雙端,但是為了這少量的程式碼把IOS和Android完全區分這明顯不合適,程式碼複用性下降,程式碼維護量上升
微信小程式在掃一掃進入小程式的時候 安卓手機後臺繼續執行的常規處理
一般在掃一掃進入小程式是沒什麼問題的 關於這個話題就不多說 怎麼去配置後臺 我的部落格裡面有提到 有興趣的可以去看看 現在是使用者第一次掃碼進入之後 退出小程式 在外部掃一掃進入小程式指定介面的時候 安卓手機就出現了一個問題 它會閃爍一下 返回的首頁去 而不是我們想要的 因為安卓手機有一個常規的操作 就是微信
Android 和IOS 混合開發,一套程式碼兩處執行-----Flutter
轉載自:https://www.jianshu.com/p/8baa8ed2414d什麼是Flutter2018年2月27日,在2018世界移動大會上,Google釋出了Flutter的第一個Beta版本。Flutter是Google用以幫助開發者在Ios和Android兩個平臺開發高質量原生應用的全新移動U
從零開始搭建Electron+Vue+Webpack專案框架,一套程式碼,同時構建客戶端、web端(一)
摘要:隨著前端技術的飛速發展,越來越多的技術領域開始被前端工程師踏足。從NodeJs問世至今,各種前端工具腳手架、服務端框架層出不窮,“全棧工程師”對於前端開發者來說,再也不只是說說而已。在NodeJs及其衍生技術高速發展的同時,Nw和Electron的問世,更是為前端發展提速不少,依稀記得哪位前輩說過,“能
【原創】從零開始搭建Electron+Vue+Webpack專案框架,一套程式碼,同時構建客戶端、web端(二)
導航: (一)Electron跑起來(二)從零搭建Vue全家桶+webpack專案框架(三)Electron+Vue+Webpack,聯合除錯整個專案(未完待續)(四)Electron配置潤色(未完待續)(五)預載入及自動更新(未完待續)(六)構建、釋出整個專案(包括client和web)(未完待續) 摘要:
微信小程式web-view元件
小程式web-view元件 不久前微信小程式釋出了web-view元件,這個訊息在各個圈裡引起不小的漣漪。近期正好在做小程式的專案,便研究了一下這個讓大家充滿期待的元件。 1,web-view這個元件是什麼鬼? 官網的介紹:web-view 元件是一個
微信小程式web-view例項
微信小程式web-view例項 index.js //index.js //獲取應用例項 const app = getApp() Page({ /** * 頁面的初始資料 */ data: { },
wechat-小程式web-view與網頁互動
wechat-小程式web-view與網頁互動. 官方api說明文件: https://developers.weixin.qq.com/miniprogram/dev/component/web-view.html 前置物料 啟動好一個網
小程式web-view使用
微信 web-view的使用: <web-view src="https://www.xxxxxxxxx.com/index.html" /> 從h5頁面跳到小程式的其他頁面: <!-- html程式碼中引入JS SDK --> <script t