vue3知识汇总

vue3.x

0. changelog

https://juejin.cn/post/7030992475271495711#heading-0

1. vite//要构建一个 Vite + Vue 项目,运行,使用 NPM:npm init @vitejs/app 项目名//使用 Yarn:yarn create @vitejs/app 项目名//你会觉得非常快速的创建了项目,然而它并没有给你下载依赖,你还有进入文件然后npm install (or yarn)2. 按需导入main.js import { createApp } from "vue";import App from "./App.vue"createApp(App).use(store).use(router).mount("#app")3. template没有了根标签4. Composition APIsetup 入口,一定要有return, 没有this, 兼容vue2的写法如:data,methods;beforeCreate和created这两个生命周期还要快; setup可以接受两个参数,第一个参数是props,也就是组件传值,第二个参数是context,上下文对象,context里面还有三个很重要的东西attrs,slots,emit,它们就相当于vue2里面的 this.$attrs, this.$slots, this.$emit。<script>export default {name: 'App',setup(){let name = '流星'let age = 18function say(){console.log(`我叫${name},今年${age}岁`)}return {name,age,say}}}</script>5. 不能使用 slot="XXX",要使用v-slot,不然会报错<template><div class="home"><HelloWorld wish="不掉发" wishes="变瘦" @carried="carried"><h3>实现插槽1</h3><template v-slot:dome><h4>实现插槽2</h4></template></HelloWorld></div></template>6. 响应式 ref & reactiveref:我们写的不是响应式数据,我们写的只是字符串和数字,那怎么变成响应式数据呢,那就呀引入ref,但是如果我们直接在代码里面修改是修改不了的,不如打印一下name和age,你会发现ref把它们变成了对象 并且还是RefImpl的实例对象<template><div class="home"><h1>姓名:{{name}}</h1><h1>年龄:{{age}}</h1><button @click="say">修改</button></div>
</template><script>
import {ref} from 'vue'
export default {name: 'Home',setup(){let name = ref('燕儿')let age = ref(18)console.log(name)console.log(age)//方法function say(){name='苒苒'age=20// name.value='苒苒'// age.value=20}return {name,age,say}}
}
</script>那么要是我定义的ref是个对象呢,因为我们知道尽管ref后会变成RefImpl的实例对象,所以我们就用XX.value.xx进行修改<template><div class="home"><h1>姓名:{{name}}</h1><h1>年龄:{{age}}</h1><h2>职业:{{job.occupation}}</h2><h2>薪资:{{job.salary}}</h2><button @click="say">修改</button></div>
</template><script>
import {ref} from 'vue'
export default {name: 'Home',setup(){let name = ref('燕儿')let age = ref(18)let job=ref({occupation:'程序员',salary:'10k'})console.log(name)console.log(age)//方法function say(){job.value.salary='12k'}return {name,age,job,say}}
}
</script>
job.value,你会发现,它不再是RefImpl实例对象,变成了Proxy实例对象; ref中是对象,自动会调用reactive。reactive:<template><div class="home"><h1>姓名:{{name}}</h1><h1>年龄:{{age}}</h1><h2>职业:{{job.occupation}}<br>薪资:{{job.salary}}</h2><h3>爱好:{{hobby[0]}},{{hobby[1]}},{{ hobby[2] }}</h3><button @click="say">修改</button></div></template><script>import {ref,reactive} from 'vue'export default {name: 'Home',setup(){let name = ref('燕儿')let age = ref(18)let job=reactive({occupation:'程序员',salary:'10k'})let hobby=reactive(['刷剧','吃鸡','睡觉'])console.log(name)console.log(age)//方法function say(){job.salary='12k'hobby[0]='学习'}return {name,age,job,say,hobby}}}</script>ref与reactive的区别ref用来定义:基本类型数据。ref通过Object.defineProperty()的get与set来实现响应式(数据劫持)。ref定义的数据:操作数据需要.value,读取数据时模板中直接读取不需要.value。reactive用来定义:对象或数组类型数据。reactive通过使用Proxy来实现响应式(数据劫持), 并通过Reflect操作源代码内部的数据。reactive定义的数据:操作数据与读取数据:均不需要.value。当然,我之前就说过,ref可以定义对象或数组的,它只是内部自动调用了reactive来转换。7. 响应式原理Proxyconst p=new Proxy(data, {// 读取属性时调用get (target, propName) {return Reflect.get(target, propName)},//修改属性或添加属性时调用set (target, propName, value) {return Reflect.set(target, propName, value)},//删除属性时调用deleteProperty (target, propName) {return Reflect.deleteProperty(target, propName)}}) 8. computed, watch, watchEffect
// computed
<template><div class="home">姓:<input type="text" v-model="names.familyName"><br>名:<input type="text" v-model="names.lastName"><br>姓名:<input type="text" v-model="names.fullName"><br></div>
</template><script>
import {reactive,computed} from 'vue'
export default {name: 'Home',setup(){let names=reactive({familyName:'阿',lastName:'斌'})names.fullName=computed({get(){return names.familyName+'.'+names.lastName},set(value){let  nameList=value.split('.')names.familyName=nameList[0]names.lastName=nameList[1]}})return {names}}
}
</script>// watch 
<template><div class="home"><h1>当前数字为:{{num}}</h1><button @click="num++">点击数字加一</button></div>
</template><script>
import {ref, watch} from 'vue'
export default {name: 'Home',setup(){let num=ref('0')watch(num,(newValue,oldValue)=>{console.log(`当前数字增加了,${newValue},${oldValue}`)})return {num}}
}
</script>
当然这是监听ref定义出来的单个响应式数据,要是监听多个数据应该怎么办呢?其实可以用多个watch去进行监听,当然这不是最好的方法,最好的办法其实是监视数组watch([num,msg],(newValue,oldValue)=>{console.log('当前改变了',newValue,oldValue)})我们现在监听的是监听ref定义出来数据,那么要是我们监听的是reactive
<template><div class="home"><h1>当前姓名:{{names.familyName}}</h1><h1>当前年龄:{{names.age}}</h1><h1>当前薪水:{{names.job.salary}}K</h1><button @click="names.familyName+='!'">点击加!</button><button @click="names.age++">点击加一</button><button @click="names.job.salary++">点击薪水加一</button></div>
</template><script>
import {reactive,watch} from 'vue'
export default {name: 'Home',setup(){let names=reactive({familyName: '鳌',age:23,job:{salary:10}})watch(()=>names.age,(newValue,oldValue)=>{console.log('names改变了',newValue,oldValue)})// 多个数据watch([()=>names.age,()=>names.familyName],(newValue,oldValue)=>{console.log('names改变了',newValue,oldValue)})// ok,要是我们监听的是深度的属性那要怎么办呢?你会发现我要是只监听第一层是监听不到的,那么我们有两种写法//第一种watch(()=> names.job.salary,(newValue,oldValue)=>{console.log('names改变了',newValue,oldValue)})//第二种watch(()=> names.job,(newValue,oldValue)=>{console.log('names改变了',newValue,oldValue)},{deep:true}) }
}
</script>// watchEffect9. 生命周期
setup里面应该这样写beforeCreate===>Not needed* setup
created=======>Not needed*  setup
beforeMount ===>onBeforeMount
mounted=======>onMounted
beforeUpdate===>onBeforeUpdate
updated =======>onUpdated
beforeUnmount ==>onBeforeUnmount
unmounted =====>onUnmounted10. hooks
Vue3 的 hook函数 相当于 vue2 的 mixin, 不同在与 hooks 是函数
Vue3 的 hook函数 可以帮助我们提高代码的复用性, 让我们能在不同的组件中都利用 hooks 函数
可以用到外部的数据,生命钩子函数11. toRefs 和 toReftoRef翻译过来其实就是把什么变成ref类型的数据,可能大家会觉得没有什么用,毕竟我们之前定义时就已经定义成ref, 那就是把name.xx变为响应式,然后操作它时会自动的去修改name里面的数据
return {name:toRef(names,'name'),age:toRef(names,'age'),salary:toRef(names.job,'salary')
}12. provider, inject
都知道组件传值吧,在vue2中,如果要在后代组件中使用父组件的数据,那么要一层一层的父子组件传值或者用到vuex,但是现在,无论组件层次结构有多深,父组件都可以作为其所有子组件的依赖提供者。这个特性有两个部分:父组件有一个 provide 选项来提供数据,子组件有一个 inject 选项来开始使用这些数据。// 父
import { provide } from 'vue'setup(){let fullname = reactive({name:'阿月',salary:'15k'})provide('fullname',fullname) // 给自己的后代组件传递数据return {...toRefs(fullname)}}// 后代
import {inject} from 'vue'setup() {let fullname = inject('fullname')return {fullname}}13. router
可能大家会想到路由跳转的问题,可能大家会以为还是用this.$router.push来进行跳转,但是哦,在vue3中,这些东西是没有的,它是定义了一个vue-router然后引入的useRoute,useRouter 相当于vue2的 this.$route,this.$router,然后其他之前vue2的操作都可以进行import {useRouter,useRoute} from "vue-router";
setup(){const router= useRouter()const route= useRoute()function fn(){this.$router.push('/about')}onMounted(()=>{console.log(route.query.code)})return{fn}
}14. 全局api的转移
app.config.xxxx
app.component
app.directive
app.mixin
app.use
app.config.globalProperties15. 其他改变
移除keyCode作为 v-on 的修饰符,同时也不再支持config.keyCodes
移除v-on.native修饰符
移除过滤器(filter)响应式判断
import {ref, reactive, readonly, isRef, isReactive, isReadonly, isProxy } from 'vue'export default {name:'App',setup(){let fullName = reactive({name:'小唐',price:'20k'})let num = ref(0)let fullNames = readonly(fullName)console.log(isRef(num))console.log(isReactive(fullName))console.log(isReadonly(fullNames))console.log(isProxy(fullName))console.log(isProxy(fullNames))console.log(isProxy(num))return {}}
}

1. 参考

https://www.bilibili.com/video/BV175411h7TN?from=search&seid=535398711802368847
https://www.bilibili.com/video/BV1JJ41137jb?from=search&seid=535398711802368847
http://www.liulongbin.top:8085
https://gitee.com/vsdeveloper/vue3-compositionAPI-studyhttps://www.bilibili.com/video/BV1LC4y1h7BF?from=search&seid=535398711802368847
https://www.bilibili.com/video/BV19C4y187Xz?from=search&seid=535398711802368847
****************************************************************************************
尤雨溪直播
https://www.bilibili.com/video/BV1Tg4y1z7FH?from=search&seid=535398711802368847
https://www.bilibili.com/video/BV1iA411J7cA?from=search&seid=535398711802368847
****************************************************************************************
源码
https://github.com/vuejs/vue-next

2. 安装

npm install -g @vue/clivue create my-projectnpm install @vue/composition-api --saveimport VueCompositionApi from '@vue/composition-api'Vue.use(VueCompositionApi)# 按需导入
const app = createApp(App)
app.use()
app.mixin()
app.component()
app.directive()因此Vue2.x的以下全局API也需要改为ES6模块化引入:
Vue.nextTick()
Vue.observable不再支持,改为reactive
Vue.version
Vue.compile (仅全构建)
Vue.set (仅兼容构建)
Vue.delete (仅兼容构建)除此之外,vuex和vue-router也都使用了Tree-Shaking进行了改进,不过api的语法改动不大
//src/store/index.js
import { createStore } from "vuex";export default createStore({state: {},mutations: {},actions: {},modules: {},
});
//src/router/index.js
import { createRouter, createWebHistory } from "vue-router";const router = createRouter({history: createWebHistory(process.env.BASE_URL),routes,
});

3. setup

setup() 函数是 vue3 中,专门为组件提供的新属性。它为我们使用 vue3 的 Composition API (组合式api)新特性提供了统一的入口。

3.1 执行时机

setup 函数会在 beforeCreate 之后、created 之前执行

3.2 props

// 在props中定义当前组件允许外界传递过来的参数名称:
props: {p1: String
}// 通过setup函数的第一个形参,接收 props 数据: 
setup(props, context) {console.log(props.p1)
}

3.3 context

setup 函数的第二个形参是一个上下文对象,这个上下文对象中包含了一些有用的属性,这些属性在vue 2.x中需要通过 this才能访问到,在vue 3.x中,它们的访问方式如下:const MyComponent = {setup(props, context) {context.attrscontext.slotscontext.parentcontext.rootcontext.emitcontext.refs}
}注意:在 setup()函数中无法访问到 this

4. reactive

定义:reactive() 函数接收一个普通对象,返回一个响应式的数据对象。

注意: 一旦return出去,后面的数据就不是响应式的了

4.1 基本语法

等价于 vue 2.x 中的 Vue.observable() 函数,vue 3.x 中提供了 reactive() 函数,用来创建响应式的数据对象,基本代码示例如下:import { reactive } from '@vue/composition-api'// 创建响应式数据对象,得到的state类似于 vue 2.x 中 data() 返回的响应式对象
const state = reactive({ count: 0 })

4.2 在template中访问

// 按需导入reactive函数:
import { reactive } from '@vue/composition-api'//在setup()函数中调用reactive()函数,创建响应式数据对象:
setup() {// 创建响应式数据对象const state = reactive({count: 0})// setup函数中将响应式数据对象 return 出去,供template使用,一旦return出去,后面的数据就不是响应式的了return state
}//在template中访问响应式数据:
<p>当前的 count 值为:{{count}}</p>

5. ref

给定的值, ref本身也是能处理对象和数组的

和 reactive 区别

5.1 基本语法

ref() 函数用来根据给定的值创建一个响应式的数据对象,ref() 函数调用的返回值是一个对象,这个对象上只包含一个 .value 属性:import { ref } from '@vue/composition-api'// 创建响应式数据对象 count,初始值为 0
const count = ref(0)// 如果要访问 ref() 创建出来的响应式数据对象的值,必须通过 .value 属性才可以
console.log(count.value) // 输出 0// 让count的值 +1
count.value++// 再次打印count的值
console.log(count.value) // 输出 1

5.2 在 template 中访问 ref 创建的响应式数据

// 在setup() 中创建响应式数据:
import { ref } from '@vue/composition-api'setup() {const count = ref(0)return {count,name: ref('zs')}
}// 在template中访问响应式数据:
<template><p>{{count}} --- {{name}}</p>
</template>

5.3 在 reactive 对象中访问 ref 创建的响应式数据

当把 ref() 创建出来的响应式数据对象,挂载到 reactive() 上时,会自动把响应式数据对象展开为原始的值,不需通过 .value 就可以直接被访问,例如:const count = ref(0)
const state = reactive({count
})console.log(state.count) // 输出 0
state.count++ // 此处不需要通过 .value 就能直接访问原始值
console.log(count) // 输出 1注意:新的ref 会覆盖 旧的ref,示例代码如下:
// 创建 ref 并挂载到 reactive 中
const c1 = ref(0)
const state = reactive({c1
})// 再次创建ref,命名为c2
const c2 = ref(9)
// 将 旧ref c1 替换为 新ref c2
state.c1 = c2
state.c1++console.log(state.c1) // 输出 10
console.log(c2.value) // 输出 10
console.log(c1.value) // 输出 0

6. isRef

isRef() 用来判断某个值是否为 ref() 创建出来的对象;应用场景:当需要展开某个可能为 ref() 创建出来的值的时候,例如:import { isRef } from '@vue/composition-api'
const unwrapped = isRef(foo) ? foo.value : foo

7. toRefs

toRefs()函数可以将reactive()创建出来的响应式对象,转换为普通的对象,只不过,这个对象上的每个属性节点,都是 ref() 类型的响应式数据,最常见的应用场景如下:import { toRefs } from '@vue/composition-api'
setup() {// 定义响应式数据对象const state = reactive({count: 0})// 定义页面上可用的事件处理函数const increment = () => {state.count++}// 在 setup 中返回一个对象供页面使用// 这个对象中可以包含响应式的数据,也可以包含事件处理函数return {// 将 state 上的每个属性,都转化为 ref 形式的响应式数据...toRefs(state),// 自增的事件处理函数increment}
}页面上可以直接访问 setup() 中 return 出来的响应式数据:
<template><div><p>当前的count值为:{{count}}</p><button @click="increment">+1</button></div>
</template>

8. computed

computed() 用来创建计算属性,computed() 函数的返回值是一个 ref 的实例。使用 computed 之前需要按需导入:import { computed } from '@vue/composition-api'

8.1 创建只读的计算属性

在调用 computed() 函数期间,传入一个 function 函数,可以得到一个只读的计算属性,示例代码如下:// 创建一个 ref 响应式数据
const count = ref(1)// 根据 count 的值,创建一个响应式的计算属性 plusOne
// 它会根据依赖的 ref 自动计算并返回一个新的 ref
const plusOne = computed(() => count.value + 1)console.log(plusOne.value) // 输出 2
plusOne.value++ // error

8.2 创建可读可写的计算属性

在调用 computed() 函数期间,传入一个包含 get 和 set 函数的对象,可以得到一个可读可写的计算属性,示例代码如下:// 创建一个 ref 响应式数据
const count = ref(1)// 创建一个 computed 计算属性
const plusOne = computed({// 取值函数get: () => count.value + 1,// 赋值函数set: val => {count.value = val - 1}
})// 为计算属性赋值的操作,会触发 set 函数
plusOne.value = 9
// 触发 set 函数后,count 的值会被更新
console.log(count.value) // 输出 8

9. watch

侦听一个深度嵌套的对象属性变化时,需要设置deep:true

这是因为侦听一个响应式对象始终返回该对象的引用,因此我们需要对值进行深拷贝: () => _.cloneDeep(deepObj)

9.1 基本使用

watch() 函数用来监视某些数据项的变化,从而触发某些特定的操作,使用之前需要按需导入:import { watch } from '@vue/composition-api'
const count = ref(0)// 定义 watch,只要 count 值变化,就会触发 watch 回调
// watch 会在创建时会自动调用一次
watch(() => console.log(count.value))
// 输出 0setTimeout(() => {count.value++// 触发watch回调,输出1
}, 1000)

9.2 监视指定的数据源

监视 reactive 类型的数据源:

// 定义数据源
const state = reactive({ count: 0 })
// 监视 state.count 这个数据节点的变化
watch(() => state.count,(count, prevCount) => {/* ... */}
)

监视 ref 类型的数据源:

// 定义数据源
const count = ref(0)
// 指定要监视的数据源
watch(count, (count, prevCount) => {/* ... */
})

9.3 监视多个数据源

监视 reactive 类型的数据源:

const state = reactive({ count: 0, name: 'zs' })watch([() => state.count, () => state.name], // Object.values(toRefs(state)),([count, name], [prevCount, prevName]) => {console.log(count) // 新的 count 值console.log(name) // 新的 name 值console.log('------------')console.log(prevCount) // 旧的 count 值console.log(prevName) // 新的 name 值},{lazy: true // 在 watch 被创建的时候,不执行回调函数中的代码}
)setTimeout(() => {state.count++state.name = 'ls'
}, 1000)

监视 ref 类型的数据源:

const count = ref(0)
const name = ref('zs')watch([count, name], // 需要被监视的多个 ref 数据源([count, name], [prevCount, prevName]) => {console.log(count)console.log(name)console.log('-------------')console.log(prevCount)console.log(prevName)},{lazy: true}
)setTimeout(() => {count.value++name.value = 'xiaomaolv'
}, 1000)

9.4 清除监视源

setup() 函数内创建的 watch 监视,会在当前组件被销毁的时候自动停止。如果想要明确地停止某个监视,可以调用 watch() 函数的返回值即可,语法如下:

// 创建监视,并得到 停止函数
const stop = watch(() => {/* ... */
})// 调用停止函数,清除对应的监视
stop()

9.5 清楚无效的异步任务

有时候,当被 watch 监视的值发生变化时,或 watch 本身被 stop 之后,我们期望能够清除那些无效的异步任务,此时,watch 回调函数中提供了一个 cleanup registrator function 来执行清除的工作。这个清除函数会在如下情况下被调用:

  • watch 被重复执行了
  • watch 被强制 stop

Template 中的代码示例如下

/* template 中的代码 */ <input type="text" v-model="keywords" />

Script 中的代码示例如下

// 定义响应式数据 keywords
const keywords = ref('')// 异步任务:打印用户输入的关键词
const asyncPrint = val => {// 延时 1 秒后打印return setTimeout(() => {console.log(val)}, 1000)
}// 定义 watch 监听
watch(keywords,(keywords, prevKeywords, onCleanup) => {// 执行异步任务,并得到关闭异步任务的 timerIdconst timerId = asyncPrint(keywords)// 如果 watch 监听被重复执行了,则会先清除上次未完成的异步任务onCleanup(() => clearTimeout(timerId))},// watch 刚被创建的时候不执行{ lazy: true }
)// 把 template 中需要的数据 return 出去
return {keywords
}

10. 生命周期钩子

新版的生命周期函数,可以按需导入到组件中,且只能在 setup() 函数中使用,代码示例如下:

import { onMounted, onUpdated, onUnmounted } from '@vue/composition-api'const MyComponent = {setup() {onMounted(() => {console.log('mounted!')})onUpdated(() => {console.log('updated!')})onUnmounted(() => {console.log('unmounted!')})}
}

下面的列表,是 vue 2.x 的生命周期函数与新版 Composition API 之间的映射关系:

  • beforeCreate -> use setup()
  • created -> use setup()
  • beforeMount -> onBeforeMount
  • mounted -> onMounted
  • beforeUpdate -> onBeforeUpdate
  • updated -> onUpdated
  • beforeDestroy -> onBeforeUnmount
  • destroyed -> onUnmounted
  • errorCaptured -> onErrorCaptured

11. provide & inject

11.1 共享普通数据

App.vue 根组件:

<template><div id="app"><h1>App 根组件</h1><hr /><LevelOne /></div>
</template><script>
import LevelOne from './components/LevelOne'
// 1. 按需导入 provide
import { provide } from '@vue/composition-api'export default {name: 'app',setup() {// 2. App 根组件作为父级组件,通过 provide 函数向子级组件共享数据(不限层级)//    provide('要共享的数据名称', 被共享的数据)provide('globalColor', 'red')},components: {LevelOne}
}
</script>

LevelOne.vue 组件:

<template><div><!-- 4. 通过属性绑定,为标签设置字体颜色 --><h3 :style="{color: themeColor}">Level One</h3><hr /><LevelTwo /></div>
</template><script>
import LevelTwo from './LevelTwo'
// 1. 按需导入 inject
import { inject } from '@vue/composition-api'export default {setup() {// 2. 调用 inject 函数时,通过指定的数据名称,获取到父级共享的数据const themeColor = inject('globalColor')// 3. 把接收到的共享数据 return 给 Template 使用return {themeColor}},components: {LevelTwo}
}
</script>

LevelTwo.vue 组件:

<template><div><!-- 4. 通过属性绑定,为标签设置字体颜色 --><h5 :style="{color: themeColor}">Level Two</h5></div>
</template><script>
// 1. 按需导入 inject
import { inject } from '@vue/composition-api'export default {setup() {// 2. 调用 inject 函数时,通过指定的数据名称,获取到父级共享的数据const themeColor = inject('globalColor')// 3. 把接收到的共享数据 return 给 Template 使用return {themeColor}}
}
</script>

11.2 共享ref响应式数据

如下代码实现了点按钮切换主题颜色的功能,主要修改了 App.vue 组件中的代码,LevelOne.vueLevelTwo.vue 中的代码不受任何改变:

<template><div id="app"><h1>App 根组件</h1><!-- 点击 App.vue 中的按钮,切换子组件中文字的颜色 --><button @click="themeColor='red'">红色</button><button @click="themeColor='blue'">蓝色</button><button @click="themeColor='orange'">橘黄色</button><hr /><LevelOne /></div>
</template><script>
import LevelOne from './components/LevelOne'
import { provide, ref } from '@vue/composition-api'export default {name: 'app',setup() {// 定义 ref 响应式数据const themeColor = ref('red')// 把 ref 数据通过 provide 提供的子组件使用provide('globalColor', themeColor)// setup 中 return 数据供当前组件的 Template 使用return {themeColor}},components: {LevelOne}
}
</script>

12. template refs

12.1 元素引用

示例代码如下:

<template><div><h3 ref="h3Ref">TemplateRefOne</h3></div>
</template><script>
import { ref, onMounted } from '@vue/composition-api'export default {setup() {// 创建一个 DOM 引用const h3Ref = ref(null)// 在 DOM 首次加载完毕之后,才能获取到元素的引用onMounted(() => {// 为 dom 元素设置字体颜色// h3Ref.value 是原生DOM对象h3Ref.value.style.color = 'red'})// 把创建的引用 return 出去return {h3Ref}}
}
</script>

12.2 组件引用

TemplateRefOne.vue 中的示例代码如下:

<template><div><h3>TemplateRefOne</h3><!-- 4. 点击按钮展示子组件的 count 值 --><button @click="showNumber">获取TemplateRefTwo中的count值</button><hr /><!-- 3. 为组件添加 ref 引用 --><TemplateRefTwo ref="comRef" /></div>
</template><script>
import { ref } from '@vue/composition-api'
import TemplateRefTwo from './TemplateRefTwo'export default {setup() {// 1. 创建一个组件的 ref 引用const comRef = ref(null)// 5. 展示子组件中 count 的值const showNumber = () => {console.log(comRef.value.count)}// 2. 把创建的引用 return 出去return {comRef,showNumber}},components: {TemplateRefTwo}
}
</script>

TemplateRefTwo.vue 中的示例代码:

<template><div><h5>TemplateRefTwo --- {{count}}</h5><!-- 3. 点击按钮,让 count 值自增 +1 --><button @click="count+=1">+1</button></div>
</template><script>
import { ref } from '@vue/composition-api'export default {setup() {// 1. 定义响应式的数据const count = ref(0)// 2. 把响应式数据 return 给 Template 使用return {count}}
}
</script>

13. 优化

1. 更快1.1 重构了 virtual dom标记静态内容,并区分动态内容更新时只diff动态的部分1.2 事件缓存cachehandles, 变成静态节点1.3 proxy的响应式对象实例化,添加,删除,修改属性等,都需要通过该代理器vue2.x object.defineProperty 来实现响应式对象vue3.x reactive, ref2. 更小2.1 tree shaking 将无用的代码都摇掉,原生的,比如按需导入, 所有的API都通过ES6模块化的方式引入,这样就能让webpack或rollup等打包工具在打包时对没有用到API进行剔除,最小化bundle体积3. 更易于维护3.1 从 flow 迁移到 typescript 类型检测,null引用,自动类型转换3.2 代码目录结构遵循monorepo将代码从src 分隔到一个个小的模块中,专注自己的几个模板

14. 新的内置组件

fragments template中内容必须由一个div包裹,直接可以省略,不会报错teleport内置标签,模态功能,遮罩<teleport> ...</teleport>suspense呈现回退内容,占位逻辑或者加载异常逻辑, 异步组件

15. 新的构建工具vite

特点:1.快速的冷启动2.即时的模块热更新3.真正的按需编译esm, 生产环境用rollup打包(tree shaking, 基于es modules)npm init vite-app xxx
npm install 
npm run dev

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1543868.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

R包安装教程,如何安装rjags和infercnv

一.介绍 在数据分析过程中&#xff0c;R语言因其强大的统计分析能力和丰富的包生态系统&#xff0c;成为众多研究人员和数据科学家的首选工具。本文将详细介绍如何在R环境中安装两个重要的R包——rjags和infercnv。rjags用于与JAGS&#xff08;Just Another Gibbs Sampler&…

基于 Amazon Bedrock +lambda函数调用大模型构建你的智能网页助手

​ 文章目录 1. 前言2. 使用到的关键产品2.1 Amazon Bedrock2.2 Amazon lambda2.3 Amazon API Gateway 3. 注册亚马逊云科技账号4. 构建大模型API4.1 调用 Amazon Bedrock4.2 使用 Amazon lambda函数4.3 调Amazon API Gateway 5. 构建应用调用API6. 总结 1. 前言 传统的大模型…

LabVIEW界面输入值设为默认值

在LabVIEW中&#xff0c;将前面板上所有控件的当前输入值设为默认值&#xff0c;可以通过以下步骤实现&#xff1a; 使用控件属性节点&#xff1a;你可以创建一个属性节点来获取所有控件的引用。 右键点击控件&#xff0c;选择“创建” > “属性节点”。 设置属性节点为“D…

怎么用gitee做一个图片仓库,在md文档中用这个图片网络地址,然后显示图片

痛因&#xff1a;我为什么要这样做&#xff0c;呃&#xff0c;我一开始图片都是存本地地址的&#xff0c;放在和这个md文档同级的assets文件夹下面&#xff0c;这样子确实当时很方便&#xff0c;复制粘贴什么也不用管&#xff0c;但是想把这个文档分享给别的人的时候&#xff0…

【有啥问啥】多臂老虎机(Multi-Armed Bandit,MAB)算法详解

多臂老虎机&#xff08;Multi-Armed Bandit&#xff0c;MAB&#xff09;算法详解 1. 引言 多臂老虎机&#xff08;Multi-Armed Bandit&#xff0c;MAB&#xff09;问题源自概率论和决策论&#xff0c;是一个经典的决策优化问题。最早提出的形式是赌场中的老虎机问题&#xff…

在线秘密基地--性能测试

根据之前的测试报告中的测试用例使用jmeter进行性能测试&#xff08;在性能测试之前&#xff0c;应先进行功能测试&#xff09;。 测试报告----功能测试_功能测试报告-CSDN博客https://blog.csdn.net/m0_74876421/article/details/141307905一、使用jmeter进行功能测试 可查看…

HDFS分布式文件系统01-HDFS架构与SHELL操作

HDFS分布式文件系统 学习目标第一课时知识点1-文件系统的分类单机文件系统网络文件系统分布式文件系统 知识点2-HDFS架构知识点3-HDFS的特点知识点4-HDFS的文件读写流程知识点5-HDFS的健壮性 第二课时知识点1-HDFS的Shell介绍HDFS Shell的语法格式如下。HDFS Shell客户端命令中…

STM32 软件触发ADC采集

0.91寸OLED屏幕大小的音频频谱&#xff0c;炫酷&#xff01; STM32另一个很少人知道的的功能——时钟监测 晶振与软件的关系&#xff08;深度理解&#xff09; STM32单片机一种另类的IO初始化方法 ADC是一个十分重要的功能&#xff0c;几乎任何一款单片机都会包含这个功能&a…

信息安全工程师(13)网络攻击一般过程

前言 网络攻击的一般过程是一个复杂且系统化的行为&#xff0c;其目标往往在于未经授权地访问、破坏或窃取目标系统的信息。 一、侦查与信息收集阶段 开放源情报收集&#xff1a;攻击者首先会通过搜索引擎、社交媒体、论坛等公开渠道获取目标的基本信息&#xff0c;如姓名、地址…

Pytest-如何将allure报告发布至公司内网

原理简介 使用Python启动HTTP服务器&#xff0c;指定一个端口号port&#xff0c;内网用户可以使用ipport访问报告。 本文章继续进阶&#xff0c;简单使用nginx进行一个代理&#xff0c;使用域名可以直接访问报告。 前情概述 Pytest-allure如何在测试完成后自动生成完整报告&am…

Axure大屏可视化模板:跨领域数据分析平台原型案例

随着信息技术的飞速发展&#xff0c;数据可视化已成为各行各业提升管理效率、优化决策过程的重要手段。Axure作为一款强大的原型设计工具&#xff0c;其大屏可视化模板在农业、园区、城市、企业数据可视化、医疗等多个领域得到了广泛应用。本文将通过几个具体案例&#xff0c;展…

生成PPT时支持上传本地的PPT模板了!

制作 PPT 时想要使用特定的 PPT 模板&#xff1f; 现在&#xff0c;歌者 PPT 的「自定义模板功能」已全面升级&#xff01;你可以轻松上传自己的本地 PPT 模板&#xff0c;无论是公司统一风格的模板&#xff0c;还是带有个人设计风格的模板&#xff0c;都能无缝导入歌者 PPT。…

什么是大数据?初学者快速入门手册

“大数据”这个词有点用词不当&#xff0c;因为它意味着预先存在的数据在某种程度上是小的&#xff08;事实并非如此&#xff09;&#xff0c;或者唯一的挑战是其庞大的规模&#xff08;规模是其中之一&#xff0c;但通常还有更多&#xff09;。简而言之&#xff0c;“大数据”…

预计2030年全球GO电工钢市场规模将达到120.6亿美元

GO电工钢&#xff0c;又称为冷轧取向电工钢。GO电工钢按重量计含硅量至少为0.6%&#xff0c;含碳量不超过0.08%&#xff0c;可含有不超过1.0%的铝&#xff0c;所含其他元素的比例并不使其具有其他合金钢的特性&#xff1b;厚度不超过0.56毫米&#xff1b;呈卷状的&#xff0c;则…

Mac端口扫描工具

文章目录 端口扫描工具域名/ip转换Lookupping功能端口扫描 端口扫描工具 Mac内置了一个网络工具 网络使用工具 按住 Command 空格 然后搜索 “网络实用工具” 或 “Network Utility” 即可 域名/ip转换Lookup ping功能 端口扫描 参考文献 端口扫描工具

小柴冲刺软考中级嵌入式系统设计师系列二、嵌入式系统硬件基础知识(1)数字电路基础

目录 一、信号特征 二、组合逻辑电路和时序逻辑电路 1、组合逻辑电路 2、时序逻辑线路 三、信号转换 1、数字集成电路的分类 2、常用电平接口技术 四、可编程逻辑器件 flechazohttps://www.zhihu.com/people/jiu_sheng 小柴冲刺嵌入式系统设计师系列总目录https://blo…

使用 TypeScript 接口优化数据结构

在现代软件开发中&#xff0c;数据结构的设计至关重要&#xff0c;它直接影响到程序的性能和可维护性。TypeScript 作为一种静态类型的超集&#xff0c;为 JavaScript 带来了类型系统&#xff0c;使得开发者可以在编译时期就发现潜在的类型错误。本文将探讨如何利用 TypeScript…

uboot无法使用nfs下载文件的问题

一、系统环境 见这篇博客。 二、问题描述 uboot使用nfs下载文件出现 “T T T”&#xff0c;一直无法下载 三、解决方法 编辑/etc/nfs.conf文件&#xff1a; sudo xed /etc/nfs.conf开启udp: udpy之后重启nfs服务器&#xff1a; sudo /etc/init.d/nfs-kernel-server re…

使用GLib进行C语言编程的实例

本文将讨论使用GLib进行编程的基本步骤&#xff0c;GLib是一个跨平台的&#xff0c;用C语言编写的3个底层库(以前是5个)的集合&#xff0c;GLib提供了多种高级的数据结构&#xff0c;如内存块、双向和单向链表、哈希表等&#xff0c;GLib还实现了线程相关的函数、多线程编程以及…

知识库管理系统的未来趋势:从单一平台到生态系统

在数字化浪潮的推动下&#xff0c;知识库管理系统&#xff08;Knowledge Base Management System, KBMS&#xff09;正逐步从传统的单一平台向更加开放、灵活、智能的生态系统转变。这一转变不仅体现了技术进步的必然结果&#xff0c;也深刻反映了市场需求的变化。本文将分析随…