再探vue3.0

Vue.createApp({
        template: `..`,
        data() {
                return { count: 100 }
        },
        methods: {..}
})

1.两个概念:计数器案例原生实现、vue实现
        编程范式:命令式、声明式
        架构模式:MVC、MVVM  

2.模板语法tempate-Mustache
template元素是一种在客户端保存内容的机制,在加载时不被渲染,可以被js实例化(显示)

<template>
        <div>{{ count }}</div>        A,基本用法
        <div>{{ count * 2 }}</div>        B,表达式
        <div>{{ String(count).split("").reverse().join("")}}</div>        
        <div>{{ getReserveCount() }}</div>        C,方法-计算属性=computed
        <div>{{ isShow = count === 0 ?  false : true }}</div>        D,三元运算
</template> 

3.vue3.0 data只能是函数:


data返回的对象会被vue响应式系统劫持proxy,之后对该对象的修改和访问都会在代理中处理
vue3中template下可以有多个根元素
v-bind="obj" 对象属性作为元素属性
v-on="{click: handleClick, mousemove: mouseMove}" 绑定多个事件
@click="handleClick($event, 'tom')"
v-show: 不能用在template标签上,<template v-show="true"> 也不会被渲染 但是已被处理
v-for="(value, key, index) in obj"
v-for="(item, index) in arr"
v-for="(num, index) in 10" //从1开始打印到10

4.diff算法

template -> VNode -> Virtual Dom -> 真实dom
differ算法:新旧VNode对比,patch更新
        没key的过程:patchUnKeyedChildren
                                尽可能的复用、修改
                                [a,b,c] [a,c,d]对比,b的位置更新未c, c的位置更新未d,
                                如果新VNode数组比旧长,就创建新节点
                                                                    短,就删除旧数组
                                性能低
        有key的过程:patchKeyedChildren
                                会基于key的变化重新排列元素顺序,并且会移除/销毁key不存在的元素
                                1.从头遍历
                                2.从尾巴遍历
                                3.旧节点遍历完了还有节点,就新增节点
                                4.新节点遍历完了还有旧节点,就移除
源码:packages\runtime-core\src\renderer.ts

5.computed:getter setter

<button @click="changeFullName">change</button>
<h2>{{fullName}}</h2>
data() {
        return {firstName: 'ting', lastName: 'liu'}
}
computed: {
       fullName: {
                get() {
                        return this.firstName + ' ' + this.lastName
                },
                set(newValue) {
                        const name = this.fullName.split(' ').reverse().join(' ')
                        this.firstName = name[0]
                        this.lastName = name[1]

                },
        }
}
methods: {
        changeFullName() {
                this.fullName = 'ting1 liu1' // 事件改变计算属性的值
        },
}

源码:packages\runtime-core\src\componentOptions.ts (methods/computed)

6.watch

<input type="text" v-model="question" />
<div @click="changeInfo">changeInfo</div>
data() {
        return { question: '', info: {name: 'lt'} }
        // 监听对象: info: {name: 'lt'} watch deep
        // 监听数组:friend: [{name: 'tom1'}, {name: 'tom2'}] 监听item.name的变化,常用在组件中,通过prop属性,再使用watch深度监听item.name
}
watch: {
        question(newVal, oldVal) { // A
                // 逻辑处理
        },
        info: {
                handler(newVal, oldVal) { // 这步 B === A
                        // 逻辑处理
                },
                deep: true, 
                immediate: true
        },
        'info.name'(newVal, oldVal) { // 只监听info的name属性变化 C
                // 逻辑处理
        }
},
created() {
        const unwatch =
        this.$watch('info', function(newVal, oldVal) {...}, {deep: true, immediate: true}) // D
        unwatch() // 表示取消监听

},
// watch function|obj|string     BD相同,B先执行
methods: {
        changeInfo() {
                this.info = {name: 'tom', age: 13}
        },
}

7.知识补充:

1.深浅拷贝: 取决于复制的是实例还是内存地址
参考文章:【 js 基础 】 深浅拷贝 - 知乎

总结:Array 的 slice 和 concat 方法 和 jQuery 中的 extend 复制方法
        他们都会复制第一层的值,对于 第一层 的值都是 深拷贝,而到 第二层 的时候 Array 的 slice 和 concat 方法就是 复制引用 ,jQuery 中的 extend 复制方法 则 取决于 你的 第一个参数, 也就是是否进行递归复制。所谓第一层 就是 key 所对应的 value 值是基本数据类型,也就像上面栗子中的name、age,而对于 value 值是引用类型 则为第二层

slice和contact对于第一层是深拷贝,但对于多层的时候,是复制的引用,所以是浅拷贝
实现深拷贝的方法:
        1.递归
        2.$.extend()
        3.JSON.parse()/JSON.stringify()

8.this

1.this出现的时机:通过字面量创建对象,没有this就是这样: 详见-This理解

var obj = {
  name: "why",
  running: function() {
    console.log(obj.name + " running");
  },
  eating: function() {
    console.log(obj.name + " eating");
  },
  studying: function() {
    console.log(obj.name + " studying");
  }
}

9.v-model修饰符

.lazy => @input -> @change
.number
.trim
<input type="text" v-model.lazy="inputVal" />

v-model自定义组件使用,
组件名: 短横线,推荐  component-a
                驼峰                ComponentA

10.小知识:

1.父->子传值 props
   父 :obj="message"
11.子 props: ['a', 'b']        props数组方式解构
     template中直接用a, b
缺点:不能做类型检查
22.子 props:{}
         'a': {type: Object, default() {return {...}}  props引用类型 default返回函数

2.<template>中属性名使用-连接,【大小写不区分,转为小写】
3.非props属性使用:
        <template> <div :class="$attrs.class">
        inheriteAttrs: false
        props: {...}
4.this.$emit('eventName') // 需要在当前页面emits: ['eventName'],

1.非父子组件通信-子孙:Provide inject
2.事件传递: 事件总线 mitt
 

11.插槽v-slot

1.slot组件页面
        <div class="flex">
                <div class="left"><slot name="left"></slot></div>
               <div class="center"><slot name="center"></slot></div>
               <div class="right"><slot :name="name"></slot></div>
        </div>
        props:{name: {type: String, default: ''}}
2.引用slot组件页面
        <slot-a>
                <template v-slot="left"><a>什么什么什么什么</a></template>
                <template #[name]><a>动次打次动次打次</a></template>
        </slot-a>
        data() {return {name: 'tom'}}

v-slot:[name] 简写为 #[name]
使用格式
        slot标签定义:
                正常布局
                <div><slot name="xxx"><slot></div>
                <div><slot :name="name"><slot></div>   props: xxx

                <template v-for="..." :key=".."><slot :item="item" :index="index"></slot>                                  </template>   作用域插槽
        使用:
                <div><template v-slot="xxx">Content<template></div>

                <div :xxx="xxx"><template #[xxx]>Content<template></div>   简写
                <slotCpn><template v-slot="scope">Content内使用</template>
                </slotCpn>    作用域插槽

vue中编译作用域:

        父级模板中的所有内容都是在父级作用域中编译的
        子级模板中的内容都是在子级作用域中编译的
        作用域插槽: 父取子数据

12.动态组件:

1.<component :is="cpn" :name="name" age="10"></component>
   cpn: 需满足Vue.components注册或组件内的components注册
2.缓存组件状态:keep-alive
        <keep-alive include="home,about"><component></component>
        前提:组件页面的name一定要对应上
        第一次进page,mounted activated都执行,
                                mounted仅执行第一次初始化,后activited
                                activited次次执行
        

13.异步加载组件:

1.defineAsyncComponent + suspense
b.<suspense>
        <template #default><cpn></cpn></template>
        <template #fallback><loading></loading></template>
   </suspense>
a.const cpn = defineAsyncComponent(()=> import(''''))
components: {cpn}

14.自定义input组件使用v-modal:

<inputBlock v-modal:name="name" v-modal:title="title"></iinputBlock>

// 组件中:
<div><input v-modal="name" /><input v-modal="title"></div>
props: {name:..., title: ....}

13.vue中不能加空格的情况:

1.vue2 组件自定义双向绑定:[update:xxx]
2.vue3 keep-alive include="home,about"

14.vue中提高首屏加载方法:

1.webpack分包打包
        import('../..').then(res=> {res.sum(10,20)})
   vue中:defineAsyncComponent 见13
        写法一:
        import { defineAsyncComponent } from 'vue'
        const aaa = defineAsyncComponent(() => import('.../....'))
        写法二: loadingComponent占位组件

const aaa = defineAsyncComponent({

  loader: import('./pages/asyncCpn.vue'),

  loadingComponent: loading,
  errorComponent: xxxx // 错误加载这个组件
  delay: 2000,  // 2s后再去加载loadingComponent

})

15.动画:

1.基本用法:
  <button @click="isShow = !isShow">切换</button>
  <transition name="tom" mode="in-out" appear>
         <h2 v-if="isShow" style="display: inline-block">哈哈哈哈</h2>
   </transition>
.tom-enter-from,
.tom-leave-to {
        opacity: 0;
}
.tom-enter-to,
.tom-leave-from {
        opacity: 1;
}
.tom-enter-active,
.tom-leave-active {
        transition: opacity 2s ease;
}

2.帧动画:
  <button @click="isShow = !isShow">切换</button>
  <transition name="tom">
         <h2 v-if="isShow" style="display: inline-block">哈哈哈哈</h2>
   </transition>
.tom-enter-active,
.tom-leave-active {
        animation: bounce 2s ease;
}
@keyframes bounce {
        0% {
                transform: scale(0)
        }
        50% {
                transform: scale(1.5)
        }
        100% {
                transform: scale(1)
        }
}

3.animate.css
  <button @click="isShow = !isShow">切换</button>
  <transition name="tom" enter-active-class="animate__animated animate_fadeInDown"
                                        leave-active-class="animate__animated animate_flipInY>
         <h2 v-if="isShow" style="display: inline-block">哈哈哈哈</h2>
   </transition>
.animate_flipInY {
        transition-direction: reverse;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值