Xn – vue3. Js | codepen demonstration

Source github/vuejs/ Vue-next Vue 3

Status:

Pre-Alpha.Closed beta version

The 20-04-17 –Betabeta

The 20-07-18 –RCA Release Candidate

20-09-18PM 11:28 → Announcing Vue 3.0 :=> v3.0.0 One Piece

This new major version of the framework provides improved performance, smaller bundle sizes, better TypeScript integration, new APIs for tackling large scale use cases, and a solid foundation for long-term future iterations of the framework.

To learn without moving

Download source: (generate packages\vue\dist\vue.global.js) (vue3.js)

git clone https://github.com/vuejs/vue-next.git
cd vue-next # and install dependencies
yarn dev # create packages\vue\dist\vue.global.js
Copy the code

Test

<! -- # new packages\vue\index.html -->
  <div id="app"></div>
  <! -- Introduce vue.global.js -->
  <script src="./dist/vue.global.js"></script>
  <script>
    Reactive; reactive; reactive; reactive
    const { createApp, reactive, computed, effect } = Vue
    // Component definition
    const XnComponent = {
      template: `<button @click="increment">Count is {{ state.count }}, double is {{ state.double }}</button>`.// Data processing
      setup(){
        Data (){return {count: 0}}
        const state = reactive({
          count: 0.double: computed(() = > state.count * 2)})// Define the method
        function increment(){
          state.count++
        }
        effect(() = > {
          / / side effects
          console.log('Numbers changed', state.count)
        })
        // Return the dependency
        return { state, increment, }
      },
    }
    // Create the app mount component XnComponent to #app
    createApp().mount(XnComponent, '#app')
  </script>
Copy the code

Vue3 is a responsive Proxy

Contrast vue2.x with object.defineProperty ()

let input = document.querySelector('#input')
let span = document.querySelector('#span')

let obj = {}
// Data hijacking
Object.defineProperty(obj, 'text', {
  configurable: true.enumerable: true.get(){
    console.log('Get value:')},set(newVal){
    console.log('Update value:', newVal)
    input.value = newVal
    span.innerHTML = newVal
  }
})
// Input listen
input.addEventListener('keyup'.e= > {
  obj.text = e.target.value
})
Copy the code

test Proxy: MDN

  1. Listen (proxy) array error (Reflect handling)/ secondary and multiple get/set issues
  2. The proxy object object nesting problem does not trigger the deeper set problem
// new Proxy(obj, handler)

/**
 * Object 类型
 */
// let obj = {name: 'xn213'}
let obj = {name: 'xn213'.location: {city: 'Beijing'}}

/**
 * Array 类型
 */
// let obj = [1, 2, 3]

let xn = new Proxy(obj, {
  get(target, key){
    console.log('Get value :', key)
    // return target[key]
    return Reflect.get(target, key, )
  },
  set(target, key, val){
    console.log(Modified value:, key, val)
    // target[key] = val
    // Return true // Return true
    return Reflect.set(target, key, val)
  }
})

/ / object
// xn.name = 'xn2113'
// console.log(xn.name) // xn2113

// 1. Object nesting does not trigger

// Changing the city of the location does not trigger city set(){}
// // Obtain value: location
// // Obtain value: location
/ / / / hangzhou
xn.location.city = 'hangzhou'
console.log(xn.location.city) / / hangzhou

// 2. Array firing multiple times

// xn.push(4)
/** push * get value length * modify value 3 4 * modify value length 4 */
 
// xn.unshift(4)
/** unshift from the front, * Get value unshift * Get value length * Get value 2 * Change value 3 3 * Get value 1 * Change value 2 2 * Get value 0 * Change value 1 1 * Change value 0 4 * Change value Length 4 */
Copy the code

Handwritten reactive ()

/ / define reactive
function reactive(target){
  // Query the cache./ / response type
  observed = new Proxy(target, baseHandler)
  // Set cache.// Return the object after the (observed) response
  return observed
}
Copy the code
// Set both caches to old and new
let toProxy = new WeakMap(a)// Query the response data based on the original data
let toRaw = new WeakMap(a)// Query the original data according to the response data
Copy the code
// Define the Handler object > baseHandler
const baseHandler = {
  get(target, key){
    // Collect dependencies and return data
    track(target, key)
  },
  set(target, key, val){
    // Return the data after triggering the update
    trigger(target, key, info)
  }
}
Copy the code

left

// Collect dependencies
function track(target, key){... }Copy the code

left

// Trigger the update
function trigger(target, key, info){... }Copy the code

left

function effect(fn, options={}){... }Copy the code

left

function createReactiveEffect(fn, options){... }Copy the code

left

function computed(fn){... }Copy the code

Simple Little Demo complete: xN-vue3.js

demo.html

  <div id="app"></div>
  <button id="btn">Point me, grow up again...</button>
  <script src="./xn-vue3.js"></script>
  <script>
    const root = document.querySelector('#app')
    const btn = document.querySelector('#btn')

    const obj = reactive({
      name: 'the apes'.age: '213'
    })
    
    let double = computed(() = > obj.age * 2)
    
    effect(() = > {
      root.innerHTML = `
        <h1>${obj.name}This year,${obj.age}Age. Times 2 is${double.value}</h1>
      `
    })
    
    btn.addEventListener('click'.() = > {
      obj.age++
    }, false)
  </script>
Copy the code

xn-vue3.js

// Set two caches
let toProxy = new WeakMap(a)// Query the response data based on the original data
let toRaw = new WeakMap(a)// Query the original data according to the response data

const isObject = val= >val ! = =null && typeof val === 'object'

// The handler object whose properties are functions that define the behavior of the agent when an operation is performed
const baseHandler = {
  get(target, key){
    const res = Reflect.get(target, key)
    // Collect dependencies
    track(target, key)
    // Recursive search
    // We can use the isObject tool
    // return typeof res == 'object' ? reactive(res) : res
    return isObject(res) ? reactive(res) : res
  },
  set(target, key, val){
    const info = {oldValue: target[key], newValue: val}
    const res = Reflect.set(target, key, val)
    // Trigger the update
    trigger(target, key, info)
    return res
  }
}

function reactive(target){
  // Query the cache
  let observed = toProxy.get(target)
  if(observed){
    return observed
  }
  if(toRaw.get(target)){
    return target
  }
  / / response type
  observed = new Proxy(target, baseHandler)
  // Set cache
  toProxy.set(target, observed)
  toRaw.set(observed, target)
  return observed
}

let effectStack = []
let targetMap = new WeakMap(a)/ / storage effect

/ / {
// target: {
// age: [] (set),
// name: [effect]
/ /}
// }

function trigger(target, key, info){
  // Trigger the update
  const depsMap = targetMap.get(target)

  if(depsMap === undefined) {return
  }
  const effects = new Set(a)const computedRunners = new Set(a)if(key){
    let deps = depsMap.get(key)
    deps.forEach(effect= > {
      if(effect.computed){
        computedRunners.add(effect)
      }else{
        effects.add(effect)
      }
    })
  }
  // const run = effect => effect()
  effects.forEach(effect= > effect())
  computedRunners.forEach(effect= > effect())
}

function track(target, key){
  let effect = effectStack[effectStack.length - 1]
  if(effect){
    let depsMap = targetMap.get(target)
    if(depsMap === undefined){
      depsMap = new Map()
      targetMap.set(target, depsMap)
    }
    let dep = depsMap.get(key)
    if(dep === undefined){
      dep = new Set()
      depsMap.set(key, dep)
    }
    if(! dep.has(effect)){ dep.add(effect) effect.deps.push(dep) } } }function effect(fn, options={}){
  let e = createReactiveEffect(fn, options)
  // Computed is not considered
  e()
  return e
}

// Higher order function
function createReactiveEffect(fn, options){
  const effect = function effect(. args){
    return run(effect, fn, args)
  }
  effect.deps = []
  effect.computed = options.computed
  effect.lazy = options.lazy
  return effect
}

function run(effect, fn, args){
  if(effectStack.indexOf(effect) === -1) {try {
      effectStack.push(effect)
      returnfn(... args) }finally {
      effectStack.pop() / / to empty}}}function computed(fn){
  // Computed is not run for the first time
  const runner = effect(fn, {computed: true.lazy: true})
  return {
    effect: runner,
    get value() {return runner()
    }
  }
}
Copy the code

The road is long…

The road is long…