• vue3入门


    vue3

    一、环境

    * 需要nodejs环境
    * 安装:npm i -g @vue/cli
    * 查看版本(需要在4.5.0以上):vue -V
    * 脚手架初始化项目:vue create my-project
        Please pick a preset:Manually select features
    

    二、setup

    1、ref
    <template>
      <div>
        <div>{{count}}</div>
        <button @click="update">按钮</button>
      </div>
    </template>
    
    <script lang="ts">
      import {defineComponent, ref} from 'vue';
    
      export default defineComponent({
        name: 'App',
        // 初始化时执行,返回对象的属性和方法,模板中可以直接使用
        setup() {
          // ref(通常用于基本数据类型):定义一个响应式数据对象
          // js中需使用响应式数据对象的value属性操作数据
          // 如果ref()传入的是一个对象,则返回值.value是一个Proxy对象
          // 模板中直接使用响应式数据对象渲染数据
          const count = ref(0)
          const update = function () {
            count.value++
          }
    
          return {
            count,
            update
          }
        }
      });
    </script>
    
    <style>
    </style>
    
    2、reactive
    <template>
      <div>
        <div>{{person}}</div>
        <button @click="update">按钮</button>
      </div>
    </template>
    
    <script lang="ts">
      import {defineComponent, reactive} from 'vue';
    
      export default defineComponent({
        name: 'App',
        setup() {
          // reactive:返回一个(深层的)响应式数据代理对象(ES6的Proxy对象)
          const person = reactive({
            name: 'linlong',
            age: 28,
            wife: {
              name: 'tongliya',
              age: 18
            }
          })
    
          const update = function () {
            person.name = 'wuxi'
            person.age = 5
            person.wife = {
              name: 'jiangsu',
              age: 28
            }
          }
    
          return {
            person,
            update
          }
        }
      });
    </script>
    
    <style>
    </style>
    
    3、一些细节知识点
    * setup在beforeCreate之前执行
    * setup中不能使用this来访问data/computed/methods/props
    * setup不能是一个async函数(async函数返回的是一个promise)
    * setup(props,{attrs,slots,emit})
        props:父组件传入的,并且props中声明的,包含的所有属性的对象
        attrs:父组件传入的,并且未在props中声明的,包含的所有属性的对象
        slots:插槽
        emit:分发事件
    

    三、响应式数据原理

    1、vue2
    // vue2需要给每个属性都添加getter和setter(Object.defineProperty())
    // vue3只需给属性是对象的添加代理操作(Proxy和Reflect)
    // 数组元素无法直接修改,须通过$set()
    Object.defineProperty(data, 'count', {
      get() {},
      set() {}
    })
    
    2、vue3
    // 通过Proxy(代理): 拦截对对象属性的(13种)操作,包括属性的读写,添加, 删除(深度的)等...
    // 通过 Reflect(反射): 动态对被代理对象的相应属性进行特定的操作
    // 数组的元素可以直接修改(arr[0]=28)
    new Proxy(data, {
      // 拦截读取属性值
      get(target, prop) {
        return Reflect.get(target, prop)
      },
      // 拦截设置属性值或添加新属性
      set(target, prop, value) {
        return Reflect.set(target, prop, value)
      },
      // 拦截删除属性
      deleteProperty(target, prop) {
        return Reflect.deleteProperty(target, prop)
      }
    })
    

    四、计算属性

    <template>
      <div>
        {{person}}<br/>
        {{personCRI}}<br/>
      </div>
    </template>
    
    <script lang="ts">
      import {defineComponent, reactive, computed} from 'vue';
    
      export default defineComponent({
        name: 'App',
        setup() {
          const person = reactive({
            name: 'linlong',
            age: 28
          })
    
          // get函数中无法直接修改响应式数据的值
          /*const personCRI = computed(() => {
            const p = {...person}
            p.age++
            return p
          })*/
    
          const personCRI = computed({
            get() {
              const p = {...person}
              p.age++
              return p
            }, set(val: any) {
              person.name = val.name
              person.age = val.age
            }
          })
          // 必须personCRI.value={}方式修改值才会走set(不是深度的)
          personCRI.value = {
            name: 'wuxi',
            age: 5
          }
    
          return {
            person,
            personCRI
          }
        }
      });
    </script>
    
    <style>
    </style>
    

    五、监听属性

    <template>
      <div>
        {{person}}<br/>
        {{count}}<br/>
        <button @click="update">按钮</button>
        <br/>
      </div>
    </template>
    
    <script lang="ts">
      import {defineComponent, ref, reactive, watch, watchEffect} from 'vue';
    
      export default defineComponent({
        name: 'App',
        setup() {
          const person = reactive({
            name: 'linlong',
            age: 28,
            wife: {
              name: 'tongliya',
              age: 18
            }
          })
    
          const count = ref(0)
    
          // ********
          /*function update() {
            person.wife.age++
          }
          watch(person, () => {
            console.log(person)
          }, {
            immediate: true,  // 是否初始化立即执行一次, 默认是false
            deep: true, // 是否是深度监视, 默认是false
          })*/
    
          // ********
          /*function update() {
            person.wife.age = 28
          }
          // 除等号之前,所有使用到的响应式数据都会监听
          // 默认 immediate: true,deep: false
          watchEffect(() => {
            person.wife.age = 1
          })*/
    
          // ********
          function update() {
            // count.value = 1
            person.wife.age = 16
          }
          // 监听ref对象可直接指定。监听reactive对象,需要通过函数指定
          watch([() => person.wife.age, count], () => {
            console.log(person)
          })
    
          return {
            person,
            count,
            update
          }
        }
      });
    </script>
    
    <style>
    </style>
    

    六、生命周期

    <template>
    <div class="about">
      <h2>msg: {{msg}}</h2>
      <hr>
      <button @click="update">更新</button>
    </div>
    </template>
    
    <script lang="ts">
    import {
      ref,
      onMounted,
      onUpdated,
      onUnmounted, 
      onBeforeMount, 
      onBeforeUpdate,
      onBeforeUnmount
    } from "vue"
    
    export default {
      beforeCreate () {
        console.log('beforeCreate()')
      },
    
      created () {
        console.log('created')
      },
    
      beforeMount () {
        console.log('beforeMount')
      },
    
      mounted () {
        console.log('mounted')
      },
    
      beforeUpdate () {
        console.log('beforeUpdate')
      },
    
      updated () {
        console.log('updated')
      },
    
      beforeUnmount () {
        console.log('beforeUnmount')
      },
    
      unmounted () {
         console.log('unmounted')
      },
      
      setup() {
        const msg = ref('abc')
    
        const update = () => {
          msg.value += '--'
        }
    
        onBeforeMount(() => {
          console.log('--onBeforeMount')
        })
    
        onMounted(() => {
          console.log('--onMounted')
        })
    
        onBeforeUpdate(() => {
          console.log('--onBeforeUpdate')
        })
    
        onUpdated(() => {
          console.log('--onUpdated')
        })
    
        onBeforeUnmount(() => {
          console.log('--onBeforeUnmount')
        })
    
        onUnmounted(() => {
          console.log('--onUnmounted')
        })
        
        return {
          msg,
          update
        }
      }
    }
    </script>
    

    七、hooks函数

    import {reactive, onMounted} from "vue"
    
    export default function (name: string, age: number) {
      const person = reactive({
        name,
        age
      })
    
      onMounted(() => {
        console.log(person)
      })
    
      return {person}
    }
    

    八、toRefs

    <script lang="ts">
      import {defineComponent, toRefs} from 'vue';
    
      export default defineComponent({
        name: 'App',
        setup() {
          const obj = {
            name: 'huangtingting',
            age: 18
          }
          // 会将对象的每一个属性都变为响应式数据(ref对象)
          const person = toRefs(obj)
    
          return {
            ...person
          }
        }
      });
    </script>
    

    九、ref的另一个作用

    <template>
      <div ref="div"></div>
    </template>
    
    <script lang="ts">
      import {defineComponent, ref, onMounted} from 'vue';
    
      export default defineComponent({
        name: 'App',
        setup() {
          // 通过ref函数获取页面元素
          const div = ref<HTMLElement | null>(null)
    
          onMounted(() => {
            console.log(div.value)
          })
    
          return {
            div
          }
        }
      });
    </script>
    
    <style>
    </style>
    

    十、shallowReactive 与 shallowRef

    浅度的reactive:对象的属性修改可以监听到,嵌套对象的属性修改不会监听到
    浅度的ref:对象修改可以监听到,对象的属性修改不会监听到
    

    十一、readonly 与 shallowReadonly

    深只读:嵌套对象的属性也是只读
    浅只读:嵌套对象的属性不是只读
    

    十二、toRaw 与 markRaw

    toRaw:将响应式数据对象转化为普通对象
    markRaw:转化的对象不能成为响应式数据
    

    十三、toRef

    toRef(响应式数据对象,'属性'):返回值是一个响应式数据,与响应式数据对象的属性双向绑定
    

    十四、customRef

    <template>
      <div>
        {{personRef}}<br/>
        <button @click="update">按钮</button>
      </div>
    </template>
    
    <script lang="ts">
      import {defineComponent, customRef} from 'vue';
    
      export default defineComponent({
        name: 'App',
        setup() {
          let person = {
            name: '',
            age: 0
          }
    
          // 自定义响应式数据
          const personRef = customRef(((track, trigger) => {
            return {
              get() {
                // 开启数据追踪
                track()
                return person
              },
              set(val: any) {
                person = val
                // 更新视图
                trigger()
              }
            }
          }))
    
    
          return {
            personRef,
            update() {
              personRef.value = {
                name: 'linlong',
                age: 28
              }
            }
          }
        }
      });
    </script>
    
    <style>
    </style>
    

    十五、provide 与 inject

    provide('名称',响应式数据):祖组件提供数据
    inject('名称'):孙组件使用数据
    

    十六、响应式数据的判断

    isRef: 检查一个值是否为一个 ref 对象
    isReactive: 检查一个对象是否是由 reactive 创建的响应式代理
    isReadonly: 检查一个对象是否是由 readonly 创建的只读代理
    isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理
    

    十七、手写API

    1、shallowReactive 与 reactive
    const reactiveHandler = {
      get (target, key) {
    
        if (key==='_is_reactive') return true
    
        return Reflect.get(target, key)
      },
    
      set (target, key, value) {
        const result = Reflect.set(target, key, value)
        console.log('数据已更新, 去更新界面')
        return result
      },
    
      deleteProperty (target, key) {
        const result = Reflect.deleteProperty(target, key)
        console.log('数据已删除, 去更新界面')
        return result
      },
    }
    
    /* 
    自定义shallowReactive
    */
    function shallowReactive(obj) {
      return new Proxy(obj, reactiveHandler)
    }
    
    /* 
    自定义reactive
    */
    function reactive (target) {
      if (target && typeof target==='object') {
        if (target instanceof Array) { // 数组
          target.forEach((item, index) => {
            target[index] = reactive(item)
          })
        } else { // 对象
          Object.keys(target).forEach(key => {
            target[key] = reactive(target[key])
          })
        }
    
        const proxy = new Proxy(target, reactiveHandler)
        return proxy
      }
    
      return target
    }
    
    
    /* 测试自定义shallowReactive */
    const proxy = shallowReactive({
      a: {
        b: 3
      }
    })
    
    proxy.a = {b: 4} // 劫持到了
    proxy.a.b = 5 // 没有劫持到
    
    
    /* 测试自定义reactive */
    const obj = {
      a: 'abc',
      b: [{x: 1}],
      c: {x: [11]},
    }
    
    const proxy = reactive(obj)
    console.log(proxy)
    proxy.b[0].x += 1
    proxy.c.x[0] += 1
    
    2、shallowRef 与 ref
    /*
    自定义shallowRef
    */
    function shallowRef(target) {
      const result = {
        _value: target, // 用来保存数据的内部属性
        _is_ref: true, // 用来标识是ref对象
        get value () {
          return this._value
        },
        set value (val) {
          this._value = val
          console.log('set value 数据已更新, 去更新界面')
        }
      }
    
      return result
    }
    
    /* 
    自定义ref
    */
    function ref(target) {
      if (target && typeof target==='object') {
        target = reactive(target)
      }
    
      const result = {
        _value: target, // 用来保存数据的内部属性
        _is_ref: true, // 用来标识是ref对象
        get value () {
          return this._value
        },
        set value (val) {
          this._value = val
          console.log('set value 数据已更新, 去更新界面')
        }
      }
    
      return result
    }
    
    /* 测试自定义shallowRef */
    const ref3 = shallowRef({
      a: 'abc',
    })
    ref3.value = 'xxx'
    ref3.value.a = 'yyy'
    
    
    /* 测试自定义ref */
    const ref1 = ref(0)
    const ref2 = ref({
      a: 'abc',
      b: [{x: 1}],
      c: {x: [11]},
    })
    ref1.value++
    ref2.value.b[0].x++
    console.log(ref1, ref2)
    
    3、shallowReadonly 与 readonly
    const readonlyHandler = {
      get (target, key) {
        if (key==='_is_readonly') return true
    
        return Reflect.get(target, key)
      },
    
      set () {
        console.warn('只读的, 不能修改')
        return true
      },
    
      deleteProperty () {
        console.warn('只读的, 不能删除')
        return true
      },
    }
    
    /* 
    自定义shallowReadonly
    */
    function shallowReadonly(obj) {
      return new Proxy(obj, readonlyHandler)
    }
    
    /* 
    自定义readonly
    */
    function readonly(target) {
      if (target && typeof target==='object') {
        if (target instanceof Array) { // 数组
          target.forEach((item, index) => {
            target[index] = readonly(item)
          })
        } else { // 对象
          Object.keys(target).forEach(key => {
            target[key] = readonly(target[key])
          })
        }
        const proxy = new Proxy(target, readonlyHandler)
    
        return proxy 
      }
    
      return target
    }
    
    /* 测试自定义readonly */
    /* 测试自定义shallowReadonly */
    const objReadOnly = readonly({
      a: {
        b: 1
      }
    })
    const objReadOnly2 = shallowReadonly({
      a: {
        b: 1
      }
    })
    
    objReadOnly.a = 1
    objReadOnly.a.b = 2
    objReadOnly2.a = 1
    objReadOnly2.a.b = 2
    
    4、isRef, isReactive 与 isReadonly
    /* 
    判断是否是ref对象
    */
    function isRef(obj) {
      return obj && obj._is_ref
    }
    
    /* 
    判断是否是reactive对象
    */
    function isReactive(obj) {
      return obj && obj._is_reactive
    }
    
    /* 
    判断是否是readonly对象
    */
    function isReadonly(obj) {
      return obj && obj._is_readonly
    }
    
    /* 
    是否是reactive或readonly产生的代理对象
    */
    function isProxy (obj) {
      return isReactive(obj) || isReadonly(obj)
    }
    
    
    /* 测试判断函数 */
    console.log(isReactive(reactive({})))
    console.log(isRef(ref({})))
    console.log(isReadonly(readonly({})))
    console.log(isProxy(reactive({})))
    console.log(isProxy(readonly({})))
    

    十八、Teleport

    <teleport to="body">
      <div>该标签会添加到body标签下</div>
    </teleport>
    

    十九、Suspense

    <template>
      <Suspense>
        <template v-slot:default>
          <llComponent></llComponent>
        </template>
        <template v-slot:fallback>
          <div>加载中...</div>
        </template>
      </Suspense>
    </template>
    
    <script lang="ts">
      import {defineComponent, defineAsyncComponent} from 'vue';
    
      export default defineComponent({
        name: 'App',
        components: {
          // 加载异步组件
          llComponent: defineAsyncComponent(() => import('./views/llComponent.vue'))
        },
        setup() {
          return {}
        }
      });
    </script>
    
    <style scoped>
    
    </style>
    
    <template>
      <div>{{msg}}</div>
    </template>
    
    <script lang="ts">
      export default {
        name: 'llComponent',
        setup() {
          return new Promise((resolve, reject) => {
            setTimeout(() => {
              resolve({
                msg: '你好,世界!'
              })
            }, 3000)
          })
        }
      }
    </script>
    
    <style scoped>
    
    </style>
    
  • 相关阅读:
    【.net】未在本地计算机上注册“microsoft.ACE.oledb.12.0”提供程序解决办法
    【JS】JavaScript中Null和undefind区别
    【SQL】SQL中on条件与where条件的区别
    【C#】C#创建自定义Object对象
    【.NET】asp.net Redirect 图片路径
    【JQ】jq动态绑定事件.on()、解绑事件off()
    【.NET】using 语句中使用的类型必须可隐式转换为"System.IDisposable"
    C# enum、int、string三种类型互相转换
    js中Date与timestamp(时间戳)的相互转换
    2. 自动化运维系列之Cobbler给Openstack节点安装操作系统。
  • 原文地址:https://www.cnblogs.com/linding/p/15079969.html
Copyright © 2020-2023  润新知