1. 程式人生 > >一套程式碼小程式&Web&Native執行的探索05——snabbdom

一套程式碼小程式&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