vue3.0学习笔记

Vue3.0重要变化

1. 更快的性能 (提升1.2到2倍)
2. 组合API (最大的亮点setup) 
3. Fragment, teleport, Suspense
4. 自定义渲染API
5. 更好的支持TS
6. 支持tree-shaking

创建项目的三种方式

    1. webpack
        git clone https://github.com/vuejs/vue-next-webpack-preview.git
        cd projectName
        npm install
        npm run dev
    2. Vue-cli
        npm install -g @vue/cli
        vue create projectName
        cd projectName
        vue add Vue-next
        npm run serve
    3. Vite (比webpack更快的,vue团队的脚手架)
        npm install -g create-vite-app
        create-vite-app projectName
        npm install (or `yarn`)
        npm run dev (or `yarn dev`)

为什么V3更快的性能

    1. diff算法 (附录1) (https://vue-next-template-explorer.netlify.app/2.0 全量比较DOM
        3.0 新增加了静态标记(PatchFlag)
        在与上次虚拟节点进行比较的时候,只对比带patch flag的节点
        并且可以通过flag的信息得知当前节点要对比的具体内容
    2. hoistStatic 静态提升(附录22.0中无论元素是否参与更新,每次都会重新创建,然后就渲染
        3.0 对不参与更新的元素,会做静态提升,只会创建一次,在渲染的时候复用
    3. cacheHandlers 事件侦听器缓存 (附录3)
        默认情况下onClick会被视为动态绑定,所以每次都会去追踪它的变化
        但是因为是同一个函数,所以没有追踪变化,直接缓存起来复用即可
    4.ssr
        当有大量静态内容时,这些内容会被当做纯字符串推进一个buffer里面
        即使存在动态的绑定,会通过模板插值嵌入进去,这样会比通过虚拟Dom渲染快很多
        当静态内容大到一定量级的时候,会用createStaticVNode方法在客户端去生成一个static node 这些node,会被直接innerHtml,不需要创建对象,然后根据对象渲染

组合API

V2存在的问题- 业务逻辑分散
// 数据和处理办法都被 methods watch computed等分隔开
export default {
    data () {
        return {
            // 购物车相关的数据定义
            shopCartList: [],
            ...
            
            // 用户相关
            user: {}
            ...
        }
    },
    methods: {
        // 购物车逻辑
        addShopCart () {},
        deleteShopCart () {},
        
        // 用户相关的逻辑
        checkUser () {},
        loginOutUser () {}
    },
    watch: {
        // 购物车相关
        shopCartList () {},
        
        // 用户相关的逻辑
        user () {},
    },
    computed: {
        // 购物车相关
        shopCartList () {},
        
        // 用户相关的逻辑
        user () {},
    }
}
V3 组合API横空出世
<!--注意点:-->
<!--1. setup 必须return出去-->
<!--2. 在内部不能使用this-->


import { ref } from 'vue'
export default { 
    // 组合API入口函数
    setup () {
      // 定义user,shopCartList相关的data 更新之后 Vue会自动更新UI
      let userName = ref('')
      let shopCartCount = ref(0)

      const updateUserName = (val) => {
        userName.value = val
      }
      const addShopCartCount = () => {
        shopCartCount.value += 1
      }
      return {
        userName,
        shopCartCount,
        updateUserName,
        addShopCartCount
      }
    }
}


// 更加复杂的业务处理 可以将单独的业务从.vue文件中分离出来
import shopCart from './setup/shopCart'
import user from './setup/user'
export default {
    // 组合API入口函数
    setup () {
      // 定义user,shopCartList相关的data 更新之后 Vue会自动更新UI
      let { userName, updateUserName} = user()
      let { shopCartCount ,  addShopCartCount} = shopCart()
      return {
        userName,
        shopCartCount,
        updateUserName,
        addShopCartCount
      }
    }
}

// user.js
import { ref } from 'vue'
function user () {
  let userName = ref('')
  const updateUserName = (val) => {
    userName.value = val
  }
  return {
    userName,
    updateUserName
  }
}
export default user

// shopCart.js
import { ref } from 'vue'
function shopCart () { 
  let shopCartCount = ref(0)
  const addShopCartCount = () => {
    shopCartCount.value += 1
  }
  return { shopCartCount ,  addShopCartCount }
}
export default shopCart

组合API:setup以及其中使用到的方法介绍

setup执行时机
beforCreated 和 created 之间
beforCreated 组件刚刚创建出来 组件的data和methods还没有初始化好
setup 是无法使用data和methods 在其中的this为undefined
created 组件刚刚创建出来,组件data和methods刚刚初始化好
setup注意点
1. setup中的this为undefined
2. setup只能是同步不能是异步
setup中使用ref,reactive,isRef, isReactive,shallowRef,shallowReactive, triggerRef, toRow, markRaw,toRef, toRefs, customRef, readonly ,shallowReadobly , isReadonly等概念
1. reactive是什么 监听复杂类型变量
    -   reacttive是vue3中提供的实现响应式数据的方法
    -   在vue2中是通过defineProperty来实现的
        在vue3中响应式数据是通过ES6的Proxy来实现的
2. reactive注意点
    -   参数必须是对象(json/arr)
    -   默认情况下修改对象不会触发界面更新
    -   想更新必修重新赋值


3. ref 监听简单类型 
    -   ref和reactive一样都是实现响应式数据的方法
    -   reactive必须传一个对象,所以一个变量想实现响应式就比较麻烦,所以ref帮助我们实现变量的响应式
    -   ref本职上还是一个reactive,系统会自动根据我们给ref传入的值将他转换
        ref(xx) => reactive({value:xxx})
    
4.  ref注意点
    在vue中使用ref的值不需要value获取
    js中使用或者赋值必须使用ref.value

5.  isRef , isReactive 判断是不是ref或者isReactive创建的

6.  shallowRef, shallowReactive 非递归监听
    -   ref 和 reactive 都是递监听的 存在的问题是性能消耗严重(每一层都会包装成proxy)所以可以使用shallow + xx 来表示非递归监听的方法
    -   * 通过shallowReactve创建的数据,只会监听第一层的变化
    -   * 通过shallowRef创建的数据,那么Vue监听的是.value的变化,而不是第一层的变化
    -   * 使用场景: 一般使用ref和reactive就可以,只有数据量比较大使用shallowRef和shallowReactive
    
7.  shallowRef本质
    ref 本质
    ref(xx) -> reactive({value:xx})
    shallowRef本质
    shallowRef(xx) -> shallowReactive({value:xx})
    * 通过shallowRef创建的数据,那么Vue监听的是.value的变化
    
8.  triggerRef会根据传入的值,更新一遍数据
    -   * v3只提供了triggerRef方法,并没有提供triggerReactive方法。
            那么reactive类型的数据,无法主动触发界面更新

9.  toRow是什么
    用来获取ref或者reactive的原始数据
    
        let obj = {name: 'jack', age: 18}
        let state = reactive(obj)
        let obj2 = toRaw(state)
        obj2 === obj
        
    如果是ref定义的 想通过toRaw处理得到原始值 要获取的是 。value的值 因为经过vue处理之后, .value中保存的才是当初创建是传入的那个原始数据
        
        let count = 1
        let state = ref(count)
        let count2 = toRaw(count.value)
        count === count2

10. markRaw是什么
    如果你希望一个数据永远都不要被监听就可以使用markRaw
    
        let obj = {name: 'jack', age: 18}
        let obj = markRaw(obj)
        let state = reactive(obj)
        修改state的值将不会引发页面相应,因为MarkRaw已经将obj变成永远无法监听的响应式数据

11. toRef是什么
    想对一个对象中的某个属性进行响应式处理
        let obj = { name: 'jack'}
        let status = toRef(obj, 'name')
        const myFun = () => {
            status.value = 'jobs'
            console.log(obj) // {name: "jobs"}
            console.log(status)
            // ObjectRefImpl {
            //  __v_isRef: true
            //  _key: "name"
            //  _object: {name: "jobs"}
            //  value: "jobs"
            // }
        }
    ref和toRef区别
        ref本质是复制,修改响应式数据不会影响以前的数据
        toRef本质是引用,修改响应式数据的值是会影响以前的数据
        ref数据变化,界面就会自动更新
        toRef数据变化,界面不会自动更新
    应用场景
        如果想让响应式数据和以前数据关联起来,并且更新响应式数据之后还不想更新UI,那么就可以使用toRef
    
        let obj = {name: 'jack', age: 18}
        let name = toRef(obj, 'name')
        
12. toRefs是什么
    想把某一个对象中的多个属性变成响应式对象
    let obj = { name: 'jack', age: 18}
    let status = toRefs(obj)
    const myFun = () => {
        status.name.value = 'jobs'
        status.age.value = 20
        console.log(obj) // {name: "jobs", age: 20}
        console.log(status) // 附件4 
    }
    
    
13. customRef是什么
    自定义ref方法
    function myRef (val) {
      return customRef((track, trigger) => {
        return {
          get () {
            track() // 告诉我们Vue 这个数据是需要追踪变化
            console.log('get', val)
            return val
          },
          set (newValue) {
            console.log('set', newValue)
            val = newValue
            trigger() // 告诉我们Vue 触发我们界面更新
          }
        }
      })
    }

14. 为什么要使用customRef 
    serup中不能使用async 但是我们确实想在其中使用就可以将异步代码写在自定义的方法里面
    let  age = myRef('../public/data.json')
    function myRef (val) {
        return customRef((track, trigger) => {
            fetch(val).then(res => {
              return res.json()
            }).then(data => {
              console.log(data)
              val = data
              trigger()
            })
            return {
              get () {
                track() // 告诉我们Vue 这个数据是需要追踪变化
                console.log('get', val)
                return val
              },
              set (newValue) {
                console.log('set', newValue)
                val = newValue
                trigger() // 告诉我们Vue 触发我们界面更新
              }
            }
        })
    }

15. ref 与 原来2.0 ref有什么区别
    在setup中不能使用$refs, 那我们如何使用ref标记的DOM
    setup () {
      const box = ref(null)
      onMounted(() => {
          console.log('onMounted', box.value)
      })
      console.log(box.value)
      return {
        box
      }
    }
    
16. setup中需要使用生命周期 从vue中引入, 上述例子中使用了 onMounted
    import { ref, onMounted } from 'vue'
    setup () {
        const box = ref(null)
        onMounted(() => {
          console.log('onMounted', box.value)
        })
        return {
            box
        }
    }
    
17. readonly
    通过readonly创建只读的数据,而且是递归只读!

18 shallowReadobly 
    通过shallowReadobly创建只有第一层是只读的数据, 不是递归只读!
    
19. isReadonly 
    是不是通过readonly创建只读的数据

Vue3.0使用的变化总结(不全)

1. 初始化Vue
原先版本
new Vue{
    el: '#root'
}3.0
Vue.createApp(Counter).mount('#root')
2. Filters 已从 Vue 3.0 中删除,不再受支持
3. v-if 与 v-for 的优先级对比

2.x 版本中在一个元素上同时使用 v-if 和 v-for 时,v-for 会优先作用

3.x 版本中 v-if 总是优先于 v-for 生效。

由于语法上存在歧义,建议避免在同一元素上同时使用两者。

比起在模板层面管理相关逻辑,更好的办法是通过创建计算属性筛选出列表,并以此创建可见元素。

4.多事件处理
只有3.0有 多事件并不是每次执行一个,而是依次执行的
<!-- 这两个 one()two() 将执行按钮点击事件 -->
<button @click="one($event), two($event)">
  Submit
</button>

one(event) {
    // first handler logic...
    console.log('one')
    this.counter++
},
two(event) {
    // second handler logic...
   console.log('two')
	this.counter++
},
three(event) {
  // second handler logic...
    console.log('three')
    this.counter++
}
5. mixin 合并机制变化
const Mixin = {
  data() {
    return {
      user: {
        name: 'Jack',
        id: 1
      }
    }
  }
}
const CompA = {
  mixins: [Mixin],
  data() {
    return {
      user: {
        id: 2
      }
    }
  }
}

2.0 
{
  user: {
    id: 2,
    name: 'Jack'
  }
}

3.0
{
  user: {
    id: 2
  }
}
6. 新版本的生命周期

3.0
在这里插入图片描述

2.0
在这里插入图片描述

7. Vue 3 中,组件现在正式支持多根节点组件,即Fragment(片段)

组件中不需要再外层加一个div

8. Vue3中, 可以只用teleport 在body下面创建元素

场景:Modal 虽然控制在组件里面但是样式实际上是在body的末尾 现在可以使用teleport方便的创建

9. Render 函数参数
// Vue 2 渲染函数示例
export default {
  render(h) {
    return h('div')
  }
}
h 是 createElement 别名

// Vue 3 渲染函数示例
import { h } from 'vue'

export default {
  render() {
    return h('div')
  }
}

附录

  1. diff只会对msg的进行对比
// 这里的flag值就是1 只有text
<div>
  <p>你好</p>
  <p>你好</p>
  <p>你好</p>
  <p>{{msg}}</p>
</div>
export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock("div", null, [
    _createVNode("p", null, "你好"),
    _createVNode("p", null, "你好"),
    _createVNode("p", null, "你好"),
    _createVNode("p", null, _toDisplayString(_ctx.msg), 1 /* TEXT */)
  ]))
}


// 这里的flag值就是3 text和class
<div>
  <p>你好</p>
  <p>你好</p>
  <p>你好</p>
  <p>{{msg}}</p>
  <p :class="{'isNew': msg='123'}">{{msg}}</p>
</div>


export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock("div", null, [
    _createVNode("p", null, "你好"),
    _createVNode("p", null, "你好"),
    _createVNode("p", null, "你好"),
    _createVNode("p", null, _toDisplayString(_ctx.msg), 1 /* TEXT */),
    _createVNode("p", {
      class: {'isNew': _ctx.msg='123'}
    }, _toDisplayString(_ctx.msg), 3 /* TEXT, CLASS */)
  ]))
}


  1. 静态提升
20 每次都会createVnode  30会把不需要的缓存下来
const _hoisted_1 = /*#__PURE__*/_createVNode("p", null, "你好", -1 /* HOISTED */)
const _hoisted_2 = /*#__PURE__*/_createVNode("p", null, "你好", -1 /* HOISTED */)
const _hoisted_3 = /*#__PURE__*/_createVNode("p", null, "你好", -1 /* HOISTED */)

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock("div", null, [
    _hoisted_1,
    _hoisted_2,
    _hoisted_3,
    _createVNode("p", null, _toDisplayString(_ctx.msg), 1 /* TEXT */),
    _createVNode("p", {
      class: {'isNew': _ctx.msg='123'}
    }, _toDisplayString(_ctx.msg), 3 /* TEXT, CLASS */)
  ]))
}

  1. 事件缓存
<div>
  <div @click="onClick"></div>
</div>


// 没有开启缓存 
export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock("div", null, [
    _createVNode("div", { onClick: _ctx.onClick }, null, 8 /* PROPS */, ["onClick"])
  ]))
}

// 开启之后
export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock("div", null, [
    _createVNode("div", {
      onClick: _cache[1] || (_cache[1] = (...args) => (_ctx.onClick(...args)))
    })
  ]))
}

  1. toRefs多个属性值
    在这里插入图片描述
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值