目录
1、应用API
1.1、component 组件
1.2、config
1.3、directive 自定义指令
1.4、provide
1.5、mixin/mount/unmount
2、全局API
2.1、h
2.2、nextTick
3、选项
3.1、Data
3.1.1、props
3.1.2、 data
3.1.3、 computed
3.1.4、 watch
3.1.5、methods/emits/expose
3.2、Dom
3.3、生命周期
3.4、选项/资源
3.4.1、directives
3.4.2、components
3.5、组合
3.5.1、setup
3.5.2、provide / inject
3.5.3、mixins
3.5.4、extends
3.6、杂项
3.6.1、name
4、实例 property
4.1、 $refs
4.2、 $attrs
5、实例方法
5.1、$watch
5.2、$emit
5.3、$forceUpdate
5.4、$nextTick
6、特殊attr
6.1、key
6.2、ref
6.3、is
7、内置组件
虚拟dom简单来说就是一个普通的JavaScript对象,包含tag,props,children三个属性
原生dom有许多属性、事件,即使创建一个空div也要付出昂贵的代价。而虚拟dom提升性能的点在于DOM发生变化的时候,通过diff算法对比,计算出需要更改的DOM,只对变化的DOM进行操作,而不是更新整个视图
Vue的数据响应式 - 知乎
vue整体流程
createApp
方法所创建的应用实例上可以使用的api
作用:声明一组可用于组件实例中的组件。
参数
{string} name
{Function | Object} [definition]
const app = createApp(App)
app.component('my-btn', { //也可以绑定数据data
template: `
`
}).mount('#index')
vue中
//可能需要在vue.config.js中配置runtimeCompiler: true,
永远不要使用用户生成的内容作为你的模板。所以试试就可以了,runtimeCompiler配置还是去掉
一个包含应用配置的对象。应用配置 | Vue.js 可以配置异常捕获等
{string} name
{Function | Object} [definition]
作用:偶尔要操作原生 DOM时
const app = Vue.createApp({
data() { return { num: 100 } },
template: ``,
});
app.directive('absTop', (el, binding) => {
el.style.top = binding.value + 'px';
});
{string | Symbol} key
value
设置一个可以被注入到应用范围内所有组件中的值。组件应该使用 inject
来接收 provide 的值。
provide
和 inject
绑定不是响应式的。这是有意为之的。不过,如果你向下传递一个响应式对象,这个对象上的 property 会保持响应式。
mixin、不建议在应用代码中使用
vuex:用来做状态管理的,里面定义的变量在每个组件中均可以使用和修改,在任一组件中修改此变量的值之后,其他组件中此变量的值也会随之修改。
Mixins:可以定义共用的变量,在每个组件中使用,引入组件中之后,各个变量是相互独立的,值的修改在组件中不会相互影响。
组件:在父组件中引入组件,相当于在父组件中给出一片独立的空间供子组件使用,然后根据props来传值,但本质上两者是相对独立的。
Mixins:则是在引入组件之后与组件中的对象和方法进行合并,相当于扩展了父组件的对象与方法,可以理解为形成了一个新的组件。
mount、所提供 DOM 元素的 innerHTML
将被替换为应用根组件的模板渲染结果。
unmount、卸载应用实例的根组件。
h函数就是vue中的createElement方法,这个函数作用就是创建虚拟dom,追踪dom变化的
vue3 h函数的使用
h('div', {class: 'mt-col'}, []), //[]可嵌套h,或直接内容
将回调推迟到下一个 DOM 更新周期之后执行。在更改了一些数据以等待 DOM 更新后立即使用它。
setup() {
const message = ref('Hello!')
const changeMessage = async newMessage => {
message.value = newMessage
await nextTick()
console.log('Now DOM is updated')
}
}
类型:Array
一个用于从父组件接收数据的数组或对象。它可以是基于数组的简单语法,也可以是基于对象的支持诸如类型检测、自定义验证和设置默认值等高阶配置的语法。
props: ['size', 'myMessage']
props: {
// 类型检查
height: Number,
// 类型检查 + 其他验证
age: {
type: Number,
default: 0,
required: true,
validator: value => {
return value >= 0
}
}
}
type:可以是String、Number、Boolean、Array、Object、Date、Function、Symbol、任何自定义构造函数、或上述内容组成的数组。
default:any 为该 prop 指定一个默认值。如果该 prop 没有被传入,则使用这个值。对象或数组的默认值必须从一个工厂函数返回
required:Boolean 定义该 prop 是否是必填项。
validator:Function 自定义验证函数会将该 prop 的值作为唯一的参数代入
类型:Function,
该函数返回组件实例的data对象。property 必须在data对象上存在才能让 Vue 将它转换为响应式的
类型:{[key: string]: Function | {get:Function, set: Function}} 对象
计算属性的结果会被缓存
类型:{[key: string]: string | Function | Object | Array} //对象
一个对象,键是要侦听的响应式 property——包含了 data 或 computed property,而值是对应的回调函数。值也可以是方法名,或者包含额外选项的对象。
methods 类型:{[key: string]: Function} 对象(键为string的fun)
不应该使用箭头函数来定义 method 函数
emits 类型:Array| Object
expose 类型:Array可以是methods方法或者属性名
将限制公共实例可以访问的 property ,反之其他property都不能被访问
export default defineComponent({
name: "test",
data() {
return {a: 2}
},
computed: {
// 仅读取
aDouble() {
return this.a * 2
},
// 读取和设置
aPlus: {
get() {
return this.a + 1
},
set(v) {
this.a = v - 1
}
}
},
methods: {
plus() { //不要用箭头函数
this.a++
}
},
watch: {
// 侦听顶级 property
a(val, oldVal) {
console.log(`new: ${val}, old: ${oldVal}`)
},
//详见:https://v3.cn.vuejs.org/api/options-data.html#watch
},
emits: {
//也可以是数组,但对象能配置事件验证
submit: (payload) => { //函数必须返回boolean
if (payload.email) {
return true
}
}
},
// plus 将被暴露,父组件则无法访问 其他property
expose: ['plus'], //可以是methods方法或者属性名
})
这些在createApp()中无法直接使用的选项都可以通过app.component来使用
const app = createApp({}) //没有具体的vue文件
app.component('my-title', {
//在这里调用选项,component本质就是加载组件,但建议使用vue文件作为组件
})
template 类型:string
一个字符串模板,用作 component 实例的标记。模板将会替换所挂载元素的 innerHTML。
render 类型:Function
字符串模板之外的另一种选择,允许你充分利用 JavaScript 的编程功能。
export default defineComponent({
render(){
return h(
'h1', // 标签名称
{class:'d-flex'} // 标签内容
)
},
template:'lalala'
})
所有生命周期钩子的 this
上下文将自动绑定至实例中,因此你可以访问 data、computed 和 methods。这意味着你不应该使用箭头函数来定义一个生命周期方法
类型:Object 声明一组可用于组件实例中的指令。
类型:Object 声明一组可用于组件实例中的组件。
export default defineComponent({
components: {Foo},
directives: {}
})
类型:Function
1、setup函数是 Composition API(组合API)的入口
2、由于在执行 setup函数的时候,是在 beforeCreate 钩子之前调用的,还没有执行 Created 生命周期方法,所以在 setup 函数中,无法使用 data 和 methods 的变量和方法
3、由于我们不能在 setup函数中使用 data 和 methods,所以 Vue 为了避免我们错误的使用,直接将 setup函数中的this修改成了 undefined
4、setup函数只能是同步的不能是异步的
5、在setup函数中定义的变量和方法最后都是需要 return 出去的 不然无法再模板中使用
参数1、props
props是响应式的,即在传入新的 props 时会对其进行更新,通过使用 watchEffect
或 watch
进行观测和响应
不能使用 ES6 解构,因为它会消除 prop 的响应性,如果需要解构 prop,可以通过使用 setup
函数中的 toRefs 来安全地完成此操作
setup(props) {
const { title } = toRefs(props)
console.log(title.value)
watchEffect(() => {
console.log(`name is: ` + props.name)
})
}
参数2、context
context上下文是一个普通的 JavaScript 对象(非响应式,可解构),它暴露三个组件的 property:
export default {
setup(props, context) {
// Attribute (非响应式对象)
console.log(context.attrs)
// 插槽 (非响应式对象)
console.log(context.slots)
// 触发事件 (方法)
console.log(context.emit)
}
//解构写法
setup(props, { attrs, slots, emit }) {
...
}
}
attrs 和 slots 是有状态的对象,它们总是会随组件本身的更新而更新。这意味着你应该避免对它们进行解构,并始终以 attrs.x 或 slots.x 的方式引用 property。请注意,与 props 不同,attrs 和 slots 是非响应式的。如果你打算根据 attrs 或 slots 更改应用副作用,那么应该在 onUpdated 生命周期钩子中执行此操作
返回值
1、返回值为 对象时, ref 在模板中访问时是被自动解开的,因此不应在模板中使用 .value
2、返回值为 渲染函数
export default {
setup() {
const readersNumber = ref(0)
const book = reactive({ title: 'Vue 3 Guide' })
return () => h('div', [readersNumber.value, book.title])
}
}
provide:类型 Object | () => Object
inject:类型 Array
这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。
//父元素
export default defineComponent({
provide: {foo: 'bar'},
})
//子组件
export default defineComponent({
inject: ['foo'], //template中{{foo}}直接调用
created() {
console.log(this.foo) // => "bar"
}
})
类型:Array
//这里的mixin也可以是一个js文件,import
const mixin = {
created() {
console.log(1)
}
}
export default defineComponent({
created() {
console.log(2)
},
mixins: [mixin]
})
注意:mixins在引入文件里都是通过this来调用属性或方法,但在vue3.0的composition API(setup中)下this是undefined。只能封装一套全新的方式来使用类似mixins的功能,我们称这种全新的方式为
自定义hooks
。
import { ref, onMounted } from 'vue'
export default function () { //封装成函数,方便传参
const aa = ref(1) //内容写法同setup
function testFn () {
console.log('testFn')
}
onMounted(() => {
testFn()
})
return {
aa //这里名称要和后面引入时保持一致
}
}
import { defineComponent, onMounted } from 'vue'
import myHooks from './myHooks'
export default defineComponent({
setup () {
const { aa } = myHooks() //这里aa名称要和前面export保持一致
onMounted(() => {
console.log('index mounted')
})
return {
aa
}
}
})
类型:Object
允许一个组件扩展到另一个组件,且继承该组件选项。mixins 选项主要用来组合功能,而 extends 主要用来考虑继承性。
和 mixins 类似,任何选项都会通过对应的合并策略被合并。
const CompA = { ... } //同样可以使用import引入
const CompB = {
extends: CompA,
}
类型:string
允许组件模板递归地调用自身,递归组件必须指定name。指定name 选项的另一个好处是便于调试
组合式Api
作用:向所有子孙组件提供数据以及提供修改数据的方法,子孙组件用inject使用数据。
$data 类型:Object,组件实例正在侦听的数据对象。
$props 类型:Object,当前组件接收到的 props 对象。
$el 类型:any,组件实例正在使用的根 DOM 元素。
$options类型:Object,当前组件实例的初始化选项。在选项中包含自定义 property 时会有用处
$parent 类型:Vue instance【仅可读】当前组件父实例,如果当前实例有的话
$root 类型:Vue instance【仅可读】当前组件树的根组件实例。如果当前实例没有父实例,此实例将会是其自己。
export default defineComponent({
name: 'son',
customOption:'12232', //自定义属性
data() {
return {a: 1, b: 2}
},
props: ['data'],
setup() {
const p = ref();
return {p}
},
mounted(): void {
console.log('$data:', this.$data) //Proxy{a: 1, b: 2}
console.log('$props:', this.$props) //Proxy{data: '1231'}
console.log('$el:', this.$el) //#text
console.log('$options:', this.$options.customOption) //12232
console.log('$parent:', this.$parent) //Proxy {…}
console.log('$root:', this.$root) //Proxy {…}'
}
})
$refs 类型:Object【仅可读】一个对象,持有注册过 ref attribute 的所有 DOM 元素和组件实例。
hello
export default defineComponent({
mounted(): void {
console.log('$refs:', this.$refs.p) //hello
}
})
$attrs 类型:Object【仅可读】包含了父作用域中不作为组件 props 或自定义事件的 attribute 绑定和事件。可以通过
v-bind="$attrs"
传入内部组件
$slots 类型:{ [name: string]: (...args: any[]) => Array| undefined }
【仅可读】以编程方式访问通过插槽分发的内容
About Me
export default defineComponent({
render() {
return h('div', [
h('header', this.$slots.header()),
])
},
created() {
console.log('$attrs:', this.$attrs)
//Proxy {data-status: 'activated', __vInternal: 1}
}
})
参数 {string | Function} source
{Function | Object} callback
{Object} [options]
返回: {Function} unwatch
侦听组件实例上的响应式 property 或函数计算结果的变化。
export default defineComponent({
setup(props){
//监视单个嵌套property
watch(() => props.data,(newVal, oldVal) => {})
}
created() {
// 顶层property 名
this.$watch('a', (newVal, oldVal) => {})
//监视单个嵌套property
this.$watch(() => this.c.d,(newVal, oldVal) => {})
//复杂property
this.$watch(() => this.a + this.b,(newVal, oldVal) => {})
}
})
参数 {string} eventName
[...args]
触发当前实例上的事件。附加参数都会传给监听器回调。
//父组件
export default defineComponent({
components: {son},
methods: {
sayHi(e) {
console.log('Hi!',e)
}
}
})
//子组件
export default defineComponent({
emits: ['welcome'],
})
迫使组件实例重新渲染。注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。
参数{Function} [callback]
将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 nextTick
一样,不同的是回调的 this
自动绑定到调用它的实例上。
除了和 v-for
一起使用外,它也可以用于强制替换元素/组件而不是重复使用它。当你遇到如下场景时它可能会很有用:
完整地触发组件的生命周期钩子
触发过渡
{{ text }} //当 text 发生改变时, 总是会被替换而不是被修改,因此会触发过渡
ref
被用来给元素或子组件注册引用信息。引用信息将会被注册在父组件的 $refs
对象上。如果在普通的 DOM 元素上使用,引用指向的就是那个 DOM 元素;如果用在子组件上,引用就指向组件实例:
hello
因为 ref 本身是作为渲染函数的结果而创建的,在初始渲染时你不能访问它们——它们还不存在!$refs
也是非响应式的,因此你不应该试图用它在模板中做数据绑定
使用动态组件。
1、当 is
attribute 被用在一个原生 HTML 元素上时,它会被作为一个自定义的内置元素进行转译
2、把 is
attribute 的值加上 vue:
前缀,这样 Vue 就会将这些元素换为 Vue 组件进行渲染
//相当于组件
内置组件可以直接在模板中使用,而不需注册。
、
、
和
和
import { KeepAlive, Teleport, Transition, TransitionGroup } from 'vue'
内置组件 | Vue.js