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 国产九九在线观看播放,俄罗斯欧美一做一级爱,国产一级毛片网站

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          Vue入門教程(一)之基本使用

          、MVVM簡介

          如果你是第一次學前端,那么本節知識一定要了解,什么是MVVM。

          MVVM是Model-View-ViewModel的簡寫。它本質上就是MVC 的改進版。MVVM 就是將其中的View 的狀態和行為抽象化,讓我們將視圖 UI 和業務邏輯分開。當然這些事 ViewModel 已經幫我們做了,它可以取出 Model 的數據同時幫忙處理 View 中由于需要展示內容而涉及的業務邏輯。MVVM的核心是ViewModel層,負責轉換Model中的數據對象來讓數據變得更容易管理和使用。是一種簡化用戶界面的事件驅動編程方式

          下邊我們來畫張圖來大體了解下MVVM的工作原理圖:

          該層向上與視圖層進行雙向數據綁定

          向下與Model層通過接口請求進行數據交互

          (1)View

          View是視圖層, 也就是用戶界面。前端主要由HTH L和csS來構建, 為了更方便地展現vi eu to del或者Hodel層的數據, 已經產生了各種各樣的前后端模板語言, 比如FreeMarker,Thyme leaf等等, 各大MV VM框架如Vue.js.Angular JS, EJS等也都有自己用來構建用戶界面的內置模板語言。

          (2)Model

          Model是指數據模型, 泛指后端進行的各種業務邏輯處理和數據操控, 主要圍繞數據庫系統展開。這里的難點主要在于需要和前端約定統一的接口規則

          (3)ViewModel

          ViewModel是由前端開發人員組織生成和維護的視圖數據層。在這一層, 前端開發者對從后端獲取的Model數據進行轉換處理, 做二次封裝, 以生成符合View層使用預期的視圖數據模型。

          View Model所封裝出來的數據模型包括視圖的狀態和行為兩部分, 而Model層的數據模型是只包含狀態的

          視圖狀態和行為都封裝在了View Model里。這樣的封裝使得View Model可以完整地去描述View層。由于實現了雙向綁定, View Model的內容會實時展現在View層, 這是激動人心的, 因為前端開發者再也不必低效又麻煩地通過操縱DOM去更新視圖。 MVVM框架已經把最臟最累的一塊做好了, 我們開發者只需要處理和維護View Model, 更新數據視圖就會自動得到相應更新,真正實現事件驅動編程。 View層展現的不是Model層的數據, 而是ViewModel的數據, 由ViewModel負責與Model層交互, 這就完全解耦了View層和Model層, 這個解耦是至關重要的, 它是前后端分離方案實施的重要一環。


          2、為什么要使用MVVM

          MVVM模式和MVC模式一樣,主要目的是分離視圖(View)和模型(Model),有幾大優點

          (1) 低耦合。視圖(View)可以獨立于Model變化和修改,一個ViewModel可以綁定到不同的"View"上,當View變化的時候Model可以不變,當Model變化的時候View也可以不變。

          (2) 可重用性。你可以把一些視圖邏輯放在一個ViewModel里面,讓很多view重用這段視圖邏輯。

          (3)獨立開發。開發人員可以專注于業務邏輯和數據的開發(ViewModel),設計人員可以專注于頁面設計,使用Expression Blend可以很容易設計界面并生成xaml代碼。

          (4)可測試。界面素來是比較難于測試的,測試可以針對ViewModel來寫


          3、VUE概述

          (1)什么是vue?

          Vue是一套用于構建用戶界面的漸進式框架。與其它大型框架不同的是,Vue 被設計為可以自底向上逐層應用。Vue 的核心庫只關注視圖層,不僅易于上手,還便于與第三方庫或既有項目整合

          這是官網給出的介紹,可能不是那么容易理解。簡單來說,Vue是一個視圖層框架,幫助我們更好的構建應用。

          使用Vue和原生JS一個最顯著的差別就是,Vue不再對DOM直接進行操作,而是通過對數據的操作,來改變頁面。使用Vue構建的頁面,是有一個個的組件組成的,當組件中定義的數據發生變化時,組件的顯示也會跟著變化,且此過程無需刷新頁面。

          (2)MVVM模式的實現者

          Model:模型層, 在這里表示JavaScript對象 View:視圖層, 在這里表示DOM(HTML操作的元素) ViewModel:連接視圖和數據的中間件, Vue.js就是MVVM中的View Model層的實現者 在MVVM架構中, 是不允許數據和視圖直接通信的, 只能通過ViewModel來通信, 而View Model就是定義了一個Observer觀察者

          ViewModel能夠觀察到數據的變化, 并對視圖對應的內容進行更新 ViewModel能夠監聽到視圖的變化, 并能夠通知數據發生改變 至此, 我們就明白了, Vue.js就是一個MV VM的實現者, 他的核心就是實現了DOM監聽與數據綁定

          (3)為什么要使用Vue

          易用:熟悉HTML、CSS、JavaScript之后,可快速度上手vue。學習曲線平穩。

          輕量級:Vue.js壓縮后有只有20多kb,超快虛擬DOM

          高效:吸取了Angular(模塊化) 和React(虛擬DOM) 的優勢, 并擁有自己獨特的功能

          開源:文檔齊全,社區活躍度高


          4、VUE之Hello World!

          步驟一:創建空文件

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>Document</title>
          </head>
          <body>
          
          </body>
          </html>

          步驟二:引入vue.js (本人下載的開發版的vue.js,跟本html文件放在了同一目錄下,所以直接引用)

          <script type="text/javascript" src="vue.js"></script>

          步驟三:創建vue實例

          <script type="text/javascript">
                  var vm = new Vue({
                      el:'#app',
                      data:{
                          msg:'Hello World'
                      }
                  });
          </script>

          步驟四:數據與頁面元素綁定

          <div id="app">
                  {{msg}}
          </div>

          完整的html

          <!DOCTYPE html>
          <html lang="en">
          <body>
              <div id="app">
                  {{msg}}
              </div>
              <script type="text/javascript" src="vue.js"></script>
              <script type="text/javascript">
                  var vm = new Vue({
                      el:'#app',
                      data:{
                          msg:'Hello World'
                      }
                  });
              </script>
          </body>
          </html>

          瀏覽器打開:

          參數分析:

          el : '#app' -- 綁定元素的ID(元素的掛載位置,值可以是CSS選擇器或者是DOM元素)

          data : { msg : 'Hello World' } -- 模型數據,屬性名:msg 值:Hello World

          {{msg}} : 在綁定的元素中使用{{ }}將Vue創建的名為msg的屬性包起來, 即可實現數據綁定功能,我們在調試狀態下手動修改下msg的值,在不刷新頁面的情況下就會展示我們修改后的值,這就是借助了Vue的數據綁定功能實現的。 MV VM模式中要求View Model層就是使用觀察者模式來實現數據的監聽與綁定, 以做到數據與視圖的快速響應

          下一篇:VUE入門教程(二)之模板語法(指令)



          于parseHTML函數代碼實在過于龐大,我這里就不一次性貼出源代碼了,大家可以前往(https://github.com/vuejs/vue/blob/dev/src/compiler/parser/html-parser.js)查看源代碼。

          我們來總結一下該函數的主要功能:

          1、匹配標簽的 "<" 字符

          匹配的標簽名稱不能是:script、style、textarea

          有如下情況:

          1、注釋標簽 /^<!\--/

          2、條件注釋 /^<!\[/

          3、html文檔頭部 /^<!DOCTYPE [^>]+>/i

          4、標簽結束 /^<\/ 開頭

          5、標簽開始 /^</ 開頭

          然后開始匹配標簽的屬性包括w3的標準屬性(id、class)或者自定義的任何屬性,以及vue的指令(v-、:、@)等,直到匹配到 "/>" 標簽的結尾。然后把已匹配的從字符串中刪除,一直 while 循環匹配。

          解析開始標簽函數代碼:

          function parseStartTag () {
             // 標簽的開始 如<div
              const start = html.match(startTagOpen)
              if (start) {
                const match = {
                  tagName: start[1], // 標簽名稱
                  attrs: [], // 標簽屬性
                  start: index // 開始位置
                }
                 // 減去已匹配的長度
                advance(start[0].length)
                let end, attr
                while (!(end = html.match(startTagClose)) && (attr = html.match(dynamicArgAttribute) || html.match(attribute))) {
                  attr.start = index
                  v
                  advance(attr[0].length)  
                  attr.end = index
                  match.attrs.push(attr) // 把匹配到的屬性添加到attrs數組
                }
                if (end) { // 標簽的結束符 ">"
                  match.unarySlash = end[1]
                  advance(end[0].length)  // 減去已匹配的長度
                  match.end = index  // 結束位置
                  return match
                }
              }
            }

          處理過后結構如下:

          接下來就是處理組合屬性,調用 “handleStartTag” 函數

           function handleStartTag (match) {
              const tagName = match.tagName // 標簽名稱
              const unarySlash = match.unarySlash // 一元標簽
              if (expectHTML) {
                if (lastTag === 'p' && isNonPhrasingTag(tagName)) {
                  // 解析標簽結束
                  parseEndTag(lastTag)
                }
                if (canBeLeftOpenTag(tagName) && lastTag === tagName) {
                  parseEndTag(tagName)
                }
              }
             // 是否為一元標簽
              const unary = isUnaryTag(tagName) || !!unarySlash
              const l = match.attrs.length
              // 標簽屬性集合
              const attrs = new Array(l)
              for (let i = 0; i < l; i++) {
                const args = match.attrs[i]
                const value = args[3] || args[4] || args[5] || ''
                const shouldDecodeNewlines = tagName === 'a' && args[1] === 'href' ? options.shouldDecodeNewlinesForHref : options.shouldDecodeNewlines
                attrs[i] = {
                  name: args[1], // 屬性名稱
                  value: decodeAttr(value, shouldDecodeNewlines) // 屬性值
                }
                if (process.env.NODE_ENV !== 'production' && options.outputSourceRange) {
                  // 開始位置
                  attrs[i].start = args.start + args[0].match(/^\s*/).length
                  // 結束位置
                  attrs[i].end = args.end
                }
              }
          
              if (!unary) {
                stack.push({ tag: tagName, lowerCasedTag: tagName.toLowerCase(), attrs: attrs, start: match.start, end: match.end })
                lastTag = tagName
              }
          		// 調用start函數
              if (options.start) {
                options.start(tagName, attrs, unary, match.start, match.end)
              }
            }

          我們簡單說一下最后調用的start函數的作用:

          1、判斷是否為svg標簽,并處理svg在ie下的兼容性問題

          2、遍歷標簽屬性,驗證其名稱是否有效

          3、標簽名是否為 style 或者 script ,如果在服務端會提示warn警告

          4、檢查屬性是否存在 v-for、v-if、v-once指令

          5、如果是更元素就驗證其合法性,不能是 slot 和 template 標簽,不能存在 v-for指令

          以上就是界面html模板的開始標簽的分析,接下來我們來分析如何匹配結束標簽。

          請看:Vue源碼全面解析三十 parseHTML函數(解析html(二)結束標簽)

          如有錯誤,歡迎指正,謝謝。

          ue的使用相信大家都很熟練了,使用起來簡單。但是大部分人不知道其內部的原理是怎么樣的,今天我們就來一起實現一個簡單的vue。

          Object.defineProperty()

          實現之前我們得先看一下Object.defineProperty的實現,因為vue主要是通過數據劫持來實現的,通過get、set來完成數據的讀取和更新。


          var obj = {name:'wclimb'}

          var age = 24

          Object.defineProperty(obj,'age',{

          enumerable: true, // 可枚舉

          configurable: false, // 不能再define

          get () {

          return age

          },

          set (newVal) {

          console.log('我改變了',age +' -> '+newVal);

          age = newVal

          }

          })

          > obj.age

          > 24

          > obj.age = 25;

          > 我改變了 24 -> 25

          > 25

          從上面可以看到通過get獲取數據,通過set監聽到數據變化執行相應操作,還是不明白的話可以去看看Object.defineProperty文檔。

          流程圖

          html代碼結構

          <div id="wrap">

          <p v-html="test"></p>

          <input type="text" v-model="form">

          <input type="text" v-model="form">

          <button @click="changeValue">改變值</button>

          {{form}}

          </div>

          js調用

          JavaScript

          new Vue({

          el: '#wrap',

          data:{

          form: '這是form的值',

          test: '<strong>我是粗體</strong>',

          },

          methods:{

          changeValue(){

          console.log(this.form)

          this.form = '值被我改變了,氣不氣?'

          }

          }

          })

          Vue結構

          class Vue{

          constructor(){}

          proxyData(){}

          observer(){}

          compile(){}

          compileText(){}

          }

          class Watcher{

          constructor(){}

          update(){}

          }

          • Vue constructor 構造函數主要是數據的初始化
          • proxyData 數據代理
          • observer 劫持監聽所有數據
          • compile 解析dom
          • compileText 解析dom里處理純雙花括號的操作
          • Watcher 更新視圖操作

          Vue constructor 初始化

          class Vue{

          constructor(options = {}){

          this.$el = document.querySelector(options.el);

          let data = this.data = options.data;

          // 代理data,使其能直接this.xxx的方式訪問data,正常的話需要this.data.xxx

          Object.keys(data).forEach((key)=> {

          this.proxyData(key);

          });

          this.methods = obj.methods // 事件方法

          this.watcherTask = {}; // 需要監聽的任務列表

          this.observer(data); // 初始化劫持監聽所有數據

          this.compile(this.$el); // 解析dom

          }

          }

          上面主要是初始化操作,針對傳過來的數據進行處理

          proxyData 代理data

          class Vue{

          constructor(options = {}){

          ......

          }

          proxyData(key){

          let that = this;

          Object.defineProperty(that, key, {

          configurable: false,

          enumerable: true,

          get () {

          return that.data[key];

          },

          set (newVal) {

          that.data[key] = newVal;

          }

          });

          }

          }

          上面主要是代理data到最上層,this.xxx的方式直接訪問data

          observer 劫持監聽

          class Vue{

          constructor(options = {}){

          ......

          }

          proxyData(key){

          ......

          }

          observer(data){

          let that = this

          Object.keys(data).forEach(key=>{

          let value = data[key]

          this.watcherTask[key] = []

          Object.defineProperty(data,key,{

          configurable: false,

          enumerable: true,

          get(){

          return value

          },

          set(newValue){

          if(newValue !== value){

          value = newValue

          that.watcherTask[key].forEach(task => {

          task.update()

          })

          }

          }

          })

          })

          }

          }

          同樣是使用Object.defineProperty來監聽數據,初始化需要訂閱的數據。

          把需要訂閱的數據到push到watcherTask里,等到時候需要更新的時候就可以批量更新數據了。下面就是;

          遍歷訂閱池,批量更新視圖。

          set(newValue){

          if(newValue !== value){

          value = newValue

          // 批量更新視圖

          that.watcherTask[key].forEach(task => {

          task.update()

          })

          }

          }

          compile 解析dom

          class Vue{

          constructor(options = {}){

          ......

          }

          proxyData(key){

          ......

          }

          observer(data){

          ......

          }

          compile(el){

          var nodes = el.childNodes;

          for (let i = 0; i 0){

          this.compile(node)

          }

          if(node.hasAttribute('v-model') && (node.tagName === 'INPUT' || node.tagName === 'TEXTAREA')){

          node.addEventListener('input',(()=>{

          let attrVal = node.getAttribute('v-model')

          this.watcherTask[attrVal].push(new Watcher(node,this,attrVal,'value'))

          node.removeAttribute('v-model')

          return () => {

          this.data[attrVal] = node.value

          }

          })())

          }

          if(node.hasAttribute('v-html')){

          let attrVal = node.getAttribute('v-html');

          this.watcherTask[attrVal].push(new Watcher(node,this,attrVal,'innerHTML'))

          node.removeAttribute('v-html')

          }

          this.compileText(node,'innerHTML')

          if(node.hasAttribute('@click')){

          let attrVal = node.getAttribute('@click')

          node.removeAttribute('@click')

          node.addEventListener('click',e => {

          this.methods[attrVal] && this.methods[attrVal].bind(this)()

          })

          }

          }

          }

          },

          compileText(node,type){

          let reg = /{{(.*)}}/g, txt = node.textContent;

          if(reg.test(txt)){

          node.textContent = txt.replace(reg,(matched,value)=>{

          let tpl = this.watcherTask[value] || []

          tpl.push(new Watcher(node,this,value,type))

          return value.split('.').reduce((val, key) => {

          return this.data[key];

          }, this.$el);

          })

          }

          }

          }

          這里代碼比較多,我們拆分看你就會覺得很簡單了

          1. 首先我們先遍歷el元素下面的所有子節點,node.nodeType === 3 的意思是當前元素是文本節點,node.nodeType === 1 的意思是當前元素是元素節點。因為可能有的是純文本的形式,如純雙花括號就是純文本的文本節點,然后通過判斷元素節點是否還存在子節點,如果有的話就遞歸調用compile方法。下面重頭戲來了,我們拆開看:


          if(node.hasAttribute('v-html')){

          let attrVal = node.getAttribute('v-html');

          this.watcherTask[attrVal].push(new Watcher(node,this,attrVal,'innerHTML'))

          node.removeAttribute('v-html')

          }

          上面這個首先判斷node節點上是否有v-html這種指令,如果存在的話,我們就發布訂閱,怎么發布訂閱呢?只需要把當前需要訂閱的數據push到watcherTask里面,然后到時候在設置值的時候就可以批量更新了,實現雙向數據綁定,也就是下面的操作

          that.watcherTask[key].forEach(task => {

          task.update()

          })

          然后push的值是一個Watcher的實例,首先他new的時候會先執行一次,執行的操作就是去把純雙花括號 -> 1,也就是說把我們寫好的模板數據更新到模板視圖上。

          最后把當前元素屬性剔除出去,我們用Vue的時候也是看不到這種指令的,不剔除也不影響

          至于Watcher是什么,看下面就知道了

          Watcher

          class Watcher{

          constructor(el,vm,value,type){

          this.el = el;

          this.vm = vm;

          this.value = value;

          this.type = type;

          this.update()

          }

          update(){

          this.el[this.type] = this.vm.data[this.value]

          }

          }

          之前發布訂閱之后走了這里面的操作,意思就是把當前元素如:node.innerHTML = ‘這是data里面的值’、node.value = ‘這個是表單的數據’

          那么我們為什么不直接去更新呢,還需要update做什么,不是多此一舉嗎?

          其實update記得嗎?我們在訂閱池里面需要批量更新,就是通過調用Watcher原型上的update方法。

          效果

          在線效果地址,大家可以瀏覽器看一下效果,由于本人太懶了,gif效果圖就先不放了,哈哈


          主站蜘蛛池模板: 国产免费一区二区视频| 精品少妇ay一区二区三区| 亚洲第一区二区快射影院| 一区二区三区精品高清视频免费在线播放 | 琪琪see色原网一区二区| 2018高清国产一区二区三区 | 精品国产AⅤ一区二区三区4区 | 日韩在线不卡免费视频一区| 精品视频一区二区三区四区五区 | 无码人妻AⅤ一区二区三区| 一区二区三区在线看| 日韩在线视频一区| 国产乱人伦精品一区二区| 日韩视频一区二区三区| 人妻少妇AV无码一区二区| 成人午夜视频精品一区| 国产成人免费一区二区三区| 国内精品一区二区三区在线观看| 中文字幕人妻第一区| 亚洲一区二区三区播放在线| 亚洲AV日韩AV天堂一区二区三区| 日本亚洲国产一区二区三区| 亚洲日韩精品一区二区三区| 国产一区二区三区在线观看精品| 一本色道久久综合一区| 午夜福利国产一区二区| 日韩精品一区二三区中文| 国产精品亚洲专区一区| 色一乱一伦一区一直爽| 日韩一区二区三区视频| 人妻免费一区二区三区最新| 国产精品美女一区二区视频| 麻豆一区二区在我观看| 国产高清一区二区三区| 国模极品一区二区三区| 精品不卡一区中文字幕| www.亚洲一区| 精品无码人妻一区二区三区品| 亚洲午夜在线一区| 国产精品一区二区久久乐下载| 国产91一区二区在线播放不卡|