Today we will discuss the vUE source code instructions and life cycle, we mainly over the next response type principle, here I would like to say one more sentence, learning source code is mainly to learn it inside the thought, thought is to achieve the algorithm, logic. So read the source code to improve our programming ability has a lot of help, learn what language is secondary, ok, now to see what needs to be prepared in front.

1. Demonstrate the instructions and life cycle of Vue2. X by hand, and simplify the rest

2. The content that has been implemented before will be used

  • Build projects using Webpack and webpack-dev-server
  • Create the study-directive directory
  • cd study-directive
  • npm init -yes
  • npm i -D webpack@5 webpack-cli@3 webpack-dev-server@3
  • Create a new webpack.config.js file
  • Copy the following configuration to webpack.config.js
const path = require('path')

module.exports = {
  / / the entry
  entry: './src/index.js'./ / export
  output: {
    // Virtual package path, that is, the folder is not actually generated, but on port 8080 virtual generation, not really physical generation
    publicPath: 'xuni'.// The name of the packaged file
    filename: 'bundle.js'
  },
  devServer: {
    / / the port number
    port: 8080.// Static resources folder
    contentBase: 'www'}}Copy the code

Create a new SRC /index.js file

alert(123)
Copy the code

Create a WWW /index.html file

<! DOCTYPEhtml>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <title>Document</title>
</head>

<body>
  <h1>Hello!!!!!!</h1>
  <script src="xuni/bundle.js"></script>
</body>

</html>
Copy the code

Add commands to package.json file:

{ "scripts": { "dev": "webpack-dev-server",}}Copy the code
  • Terminal operationnpm run dev
  • Access:http://localhost:8080/ 和 http://127.0.0.1:8080/xuni/bundle.jsAs you can seewww/index.html 和 xuni/bundle.jsContents of the document

precondition

  • willVue2. X data response principleData responsively-related modules implemented in thesrcdirectory
  • Article address: juejin.cn/post/702634…

implementation

  • www/index.html– Test data
<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, Initial - scale = 1.0 "> < title > Document < / title > < / head > < body > < div id =" app "> hello {{B.M.N}} < ul > < li > A < / li > < li > B < / li > < li > C < / li > < / ul > < input type = "text" v - model = "B.M.N" > < br > < / div > < button onclick = "add ()" > as I + 1 < / button > < script src="xuni/bundle.js"></script> <script> var vm = new Vue({ el: '#app', data: { a: 10, b: { m: { n: 7 } } }, watch: {{a () the console. The log (' a changed ')}}}) function to the add () {vm. B.M.N + +} < / script > < / body > < / HTML >Copy the code
  • src/index.jsVueHang to the global objectWindow 上
import Vue from './Vue' 
window.Vue = Vue
Copy the code
  • src/Vue.js – VueClass implementation (used to implement reactive binding of dataobserve 和 WatcherModule)
import Compiler from './Compiler'
import observe from './observe'
import Watcher from './Watcher'
export default class Vue {
  constructor(options) {
    // Save the options object as $options
    this.$options = options || {}
    / / data
    this._data = options.data || undefined
    // Make the data responsive
    observe(this._data)
    // Default data becomes responsive, which is the life cycle
    this._initData()
    // Call default watch
    this._initWatch()
    // Template compilation
    new Compiler(options.el, this)}_initData() {
    var self = this
    Object.keys(this._data).forEach((key) = > {
      Object.defineProperty(self, key, {
        get() {
          return self._data[key]
        },
        set(newValue) {
          self._data[key] = newValue
        }
      })
    })
  }
  _initWatch() {
    var self = this
    var watch = this.$options.watch
    Object.keys(watch).forEach((key) = > {
      new Watcher(self, key, watch[key])
    })
  }
}
Copy the code
  • src/Compiler.js– Template compilation
import Watcher from './Watcher'
export default class Compiler {
  constructor(el, vue) {
    / / the vue instance
    this.$vue = vue
    / / the mount point
    this.$el = document.querySelector(el)
    // If the user passes in a mount point
    if (this.$el) {
      // Call the function to make the node fragment, similar to tokens in Mustache
      // Actually use AST, which is a lightweight fragment
      let $fragment = this.node2Fragment(this.$el)
      // Compile the template
      this.compile($fragment)
      // Replace the content to the tree
      this.$el.appendChild($fragment)
    }
  }

  node2Fragment(el) {
    var fragment = document.createDocumentFragment()
    var child
    // Fragment all DOM nodes in el
    while ((child = el.firstChild)) {
      fragment.appendChild(child)
    }
    return fragment
  }

  compile(el) {
    // Get the child element
    var childNodes = el.childNodes
    var self = this
    var reg = / \ {\ {(. *) \} \} /
    childNodes.forEach((node) = > {
      var text = node.textContent
      if (node.nodeType === 1) {
        self.compileElement(node)
      } else if (node.nodeType === 3 && reg.test(text)) {
        let name = text.match(reg)[1]
        self.compileText(node, name)
      }
    })
  }

  compileElement(node) {
    // The convenience here is that you are not talking about HTML structures as strings, but as real property lists
    var nodeAttrs = node.attributes
    // Class array objects become arrays; [].slice.call(nodeAttrs).forEach((attr) = > {
      // Parse instructions here
      var attrName = attr.name
      var attrValue = attr.value
      // All commands start with v-
      var dir = attrName.substring(2)
      Attrname.startswith ('v-')
      if (attrName.indexOf('v-') = = =0) {
        // start with v-
        if (dir === 'model') {
          new Watcher(this.$vue, attrValue, (value) = > {
            node.value = value
          })
          var v = this.getVueVal(this.$vue, attrValue)
          node.value = v
          node.addEventListener('input'.(e) = > {
            var newVal = e.target.value
            this.setVueVal(this.$vue, attrValue, newVal)
          })
        } else if (dir === 'if') {}}})}compileText(node, name) {
    node.textContent = this.getVueVal(this.$vue, name)
    new Watcher(this.$vue, name, (value) = > {
      node.textContent = value // A view update is triggered})}getVueVal(vue, exp) {
    var val = vue
    exp = exp.split('. ')
    exp.forEach((k) = > {
      val = val[k]
    })
    return val
  }

  setVueVal(vue, exp, value) {
    var val = vue
    exp = exp.split('. ')
    exp.forEach((k, i) = > {
      if (i < exp.length - 1) {
        val = val[k]
      } else {
        val[k] = value
      }
    })
  }
}
Copy the code

Example source code:

Gitee.com/yokeney/vue…