Vue3 学习笔记(八)——Vue语法
一、Vue数据类型
1、基础类型
Number(数字)、String(字符串)、Boolean(布尔)、Date(日期)、Array(数组)、Object(基础对象)。
2、其他类型
Function(方法)、Symbol(属性)。
3、自定义类型
class Person {
constructor(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
}
二、控件数据绑定
1、文本赋值(文本插值)
1)对象赋值为“js变量”,解析为文本
最基本的数据绑定形式是文本插值,它使用的是“Mustache”语法 (即双大括号):
<span>Message: {{ msg }}</span> // 使用双括号把js中的变量括起来,msg会随js中的变量变化而变化
2)对象赋值为“js变量”,解析为Html字符串
<p>Using text interpolation: {{ rawHtml }}</p> // 解析为文本;Using text interpolation: <span style="color: red">This should be red.</span>
<p>Using v-html directive: <span v-html="rawHtml"></span></p> // 解析为Html字符串;Using v-html directive: This should be red.
注:v-html
不能用来拼接组合模板(如拼接多个Vue组件)
2、Attribute 绑定(控件属性赋值)
方式一:
使用 v-bind
指令;如果绑定的值是 null
或者 undefined
,那么该 attribute 将会从渲染的元素上移除。
<div v-bind:id="dynamicId"></div>
方式二:简写
<div :id="dynamicId"></div>
3、动态绑定多个值(控件绑定数据)
通过不带参数的 v-bind
进行绑定
<div v-bind="objectOfAttrs"></div>
...
data() {
return {
objectOfAttrs: {
id: 'container',
class: 'wrapper'
}
}
}
4、使用JavaScript表达式
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div :id="`list-${id}`"></div>
<!-- 这是一个语句,而非表达式 -->
{{ var a = 1 }}
<!-- 条件控制也不支持,请使用三元表达式 -->
{{ if (ok) { return message } }}
5、调用函数
<span :title="toTitleDate(date)">
{{ formatDate(date) }}
</span>
<el-button type="primary" @click="onSubmit">Create</el-button>
注:受限的全局访问:
模板中的表达式将被沙盒化,仅能够访问到有限的全局对象列表。该列表中会暴露常用的内置全局对象,比如 Math
和 Date
。
没有显式包含在列表中的全局对象将不能在模板内表达式中访问,例如用户附加在 window
上的属性。然而,你也可以自行在 app.config.globalProperties
上显式地添加它们,供所有的 Vue 表达式使用。
6、绑定响应式事件(计算属性;可以看作是一种特殊的方法)
1)计算属性放在computed
事件中,代替methods
中的方法不可响应式更新到标签中。
<p>Has published books:</p>
<span>{{ publishedBooksMessage }}</span>
export default {
data() {
return {
author: {
name: 'John Doe',
books: [
'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'
]
}
}
},
computed: {
// 一个计算属性的 getter
publishedBooksMessage() {
// `this` 指向当前组件实例
return this.author.books.length > 0 ? 'Yes' : 'No'
}
}
}
2)计算属性默认是只读的。当你尝试修改一个计算属性时,你会收到一个运行时警告。只在某些特殊场景中你可能才需要用到“可写”的属性,你可以通过同时提供 getter 和 setter 来创建“可写计算属性”:
export default {
data() {
return {
firstName: 'John',
lastName: 'Doe'
}
},
computed: {
fullName: {
// getter
get() {
return this.firstName + ' ' + this.lastName
},
// setter
set(newValue) {
// 注意:我们这里使用的是解构赋值语法
[this.firstName, this.lastName] = newValue.split(' ')
}
}
}
}
注:
① Getter 不应有副作用,如:在 getter 中做异步请求或者更改 DOM;getter 的职责应该仅为计算和返回该值。可通过监听器来扩展副作用。
② 避免直接修改计算属性值,计算属性的返回值应该被视为只读的,并且永远不应该被更改。应该更新它所依赖的源状态以触发新的计算。
三、指令 Directives
1、v-if与v-else-if、v-else
条件渲染
<!-- v-if示例 -->
<p v-if="seen">Now you see me</p>
<!-- v-if、v-else-if、v-else示例 -->
<div v-if="Math.random() > 0.8">Now you see me</div>
<div v-else-if="Math.random() > 0.5">Now you see me</div>
<div v-else>Now you don't</div>
<!-- 切换不止一个元素进行“条件渲染”时的方案:使用<template>进行包裹;v-show 不支持在 <template> 元素上使用-->
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
2、v-show
元素的可见性
<h1 v-show="ok">Hello!</h1>
3、v-text
更新元素的文本内容
<!-- v-text 通过设置元素的 textContent 属性来工作,因此它将覆盖元素中所有现有的内容。 -->
<span v-text="msg"></span>
<!-- 等同于 -->
<span>{{msg}}</span>
4、v-html
更新元素的innerHTML
<div v-html="html"></div>
5、v-pre
跳过该元素及其子元素的编译(原分不动的输出内容)
下面示例的“原始双大括号标签”及“内容”都将被保留。
<span v-pre>{{ this will not be compiled }}</span>
6、v-bind
数据绑定
<a v-bind:href="url"> ... </a>
<!-- 简写为: -->
<a :href="url"> ... </a>
<!--
动态参数绑定
举例:如果你的组件实例有一个数据属性 attributeName,其值为 "href",那么这个绑定就等价于 v-bind:href
注意,参数表达式有一些约束,
参见下面“动态参数值的限制”与“动态参数语法的限制”章节的解释
-->
<a v-bind:[attributeName]="url"> ... </a>
<a :[attributeName]="url"> ... </a>
7、v-model
数据双向绑定
1)简单示例
<!-- 示例一:页面元素或表单数据的绑定Start -->
<!-- 不使用v-model时 -->
<input
:value="text"
@input="event => text = event.target.value">
<!-- 使用v-model时 -->
<input v-model="text">
<!-- 示例一:页面元素或表单数据的绑定End -->
<!-- 示例二:组件使用v-model_Start -->
<!--①将内部原生 <input> 元素的 value attribute 绑定到 modelValue prop
②当原生的 input 事件触发时,触发一个携带了新值的 update:modelValue 自定义事件 -->
<!-- CustomInput.vue -->
<script>
export default {
props: ['modelValue'],
emits: ['update:modelValue']
}
</script>
<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>
<!-- 组件使用的地方 -->
<CustomInput v-model="searchText" />
<!-- 示例二:组件使用v-model_End -->
2)多行文本使用v-model
,需结合placeholder="add multiple lines"
使用
<template>
<span>Multiline message is:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<textarea v-model="message" placeholder="add multiple lines"></textarea>
</template>
<script>
export default {
data() {
return {
message: ''
}
}
}
</script>
注:注意在 <textarea>
中是不支持插值表达式的,如:<textarea>{{ text }}</textarea>
。
3)复选框使用v-model
① 在复选框中使用v-model
时一般赋值为布尔值
;但是也可以赋值为数组,会把复选框勾选结果作为该数组的一个元素
。
② 复选框的值绑定使用true-value
和false-value
,true-value
和false-value
仅支持和v-model
配套使用。
<template>
<!-- 普通用法 v-model=布尔值 -->
<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>
<!-- 值绑定用法1:true-value="yes"、false-value="no";这里 toggle 属性的值会在选中时被设为 'yes',取消选择时设为 'no' -->
<input type="checkbox" v-model="toggle"
true-value="yes" false-value="no" />
<!-- 值绑定用法2:给true-value、false-value绑定js数据 -->
<input type="checkbox" v-model="toggle"
:true-value="dynamicTrueValue" :false-value="dynamicFalseValue" />
<!-- 特殊用法 v-model=数组 -->
<div>Checked names: {{ checkedNames }}</div>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames" />
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames" />
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames" />
<label for="mike">Mike</label>
</template>
<script>
export default {
data() {
return {
checked: true,
checkedNames: []
}
}
}
</script>
4)单选按钮使用v-model
① 在复选框中使用v-model
时一般赋值为布尔值
,value代表当前值;
② 复选框的值绑定使用v-model
+:value
。
<template>
<!-- 普通示例 -->
<div>Picked: {{ picked }}</div>
<input type="radio" id="one" value="One" v-model="picked" />
<label for="one">One</label>
<input type="radio" id="two" value="Two" v-model="picked" />
<label for="two">Two</label>
<!-- 值绑定示例;值绑定使用 v-model+:value;pick 会在第一个按钮选中时被设为 first,在第二个按钮选中时被设为 second -->
<input type="radio" v-model="pick" :value="first" />
<input type="radio" v-model="pick" :value="second" />
</template>
<script>
export default {
data() {
return {
picked: 'One'
}
}
}
</script>
5)选择器使用v-model
<template>
<!-- 单选 -->
<span> Selected: {{ selected }}</span>
<select v-model="selected">
<option disabled value="">Please select one</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<!-- 多选 -->
<div>Selected: {{ selected }}</div>
<select v-model="selected" multiple>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<!-- 值绑定示例;当某个选项被选中,selected 会被设为该对象字面量值 { number: 123 }。 -->
<select v-model="selected">
<!-- 内联对象字面量 -->
<option :value="{ number: 123 }">123</option>
</select>
</template>
<script>
export default {
data() {
return {
selected: '',
selected: []
}
}
}
</script>
6)组件上使用v-model
① 组件简单使用v-model
<CustomInput v-model="searchText" />
组件内处理方式1:
<!-- CustomInput.vue -->
<script>
export default {
props: ['modelValue'],
emits: ['update:modelValue'],
computed: {
value: {
get() {
return this.modelValue
},
set(value) {
this.$emit('update:modelValue', value)
}
}
}
}
</script>
<template>
<input v-model="value" />
</template>
组件内处理方式2(简写方式一):
<!-- CustomInput.vue -->
<script>
export default {
props: ['modelValue'],
emits: ['update:modelValue']
}
</script>
<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>
② 组件使用多个v-model
多写几个props
和emits
就好。
<UserName v-model:first-name="first" v-model:last-name="last"/>
<!-- UserName.vue -->
<template>
<input
type="text"
:value="firstName"
@input="$emit('update:firstName', $event.target.value)"
/>
<input
type="text"
:value="lastName"
@input="$emit('update:lastName', $event.target.value)"
/>
</template>
<script>
export default {
props: {
firstName: String,
lastName: String
},
emits: ['update:firstName', 'update:lastName']
}
</script>
7)v-model
的一些修饰符
①.lazy
:默认情况下,v-model
会在每次 input
事件后更新数据 (IME 拼字阶段的状态例外)。你可以添加 lazy
修饰符来改为在每次 change
事件后更新数据。如:<input v-model.lazy="msg" />
;
②.number
:如果你想让用户输入自动转换为数字,你可以在 v-model
后添加 .number
修饰符来管理输入。如:<input v-model.number="age" />
;
注:如果该值无法被 parseFloat()
处理,那么将返回原始值。number
修饰符会在输入框有 type="number"
时自动启用。
③.trim
:如果你想要默认自动去除用户输入内容中两端的空格,你可以在 v-model
后添加 .trim
修饰符。如:<input v-model.trim="msg" />
;
8)自定义修饰符
<MyComponent v-model.capitalize="myText" />
<!-- MyComponent -->
<template>
<!-- 定义:value与@input事件 -->
<input type="text" :value="modelValue" @input="emitValue" />
</template>
<script>
export default {
props: {
modelValue: String, //
modelModifiers: { // 修饰符组
default: () => ({})
}
},
emits: ['update:modelValue'],
methods: {
emitValue(e) { // input事件中写我们自定义的修饰符的处理逻辑
let value = e.target.value
if (this.modelModifiers.capitalize) { // 使用了自定义的capitalize修饰符时,如:<MyComponent v-model.capitalize="myText" />
value = value.charAt(0).toUpperCase() + value.slice(1) // 处理逻辑
}
this.$emit('update:modelValue', value)
}
}
}
</script>
注:对于又有参数又有修饰符的 v-model
绑定,生成的 prop 名将是 arg + "Modifiers"
。举例来说:<MyComponent v-model:title.capitalize="myText">
对应的声明就是:
export default {
props: ['title', 'titleModifiers'],
emits: ['update:title'],
created() {
console.log(this.titleModifiers) // { capitalize: true }
}
}
8、v-for
数据循环赋值
注意v-if
比 v-for
的优先级更高。这意味着 v-if
的条件将无法访问到 v-for
作用域内定义的变量别名。
1)页面控件使用示例:
<!-- v-for示例一;循环10次;注:此处 n 的初值是从 1 开始而非 0。 -->
<span v-for="n in 10">{{ n }}</span>
<!-- v-for示例二;注:v-for="item of items"也是可以的 -->
<div v-for="item in items">{{ item.text }}</div>
<!-- v-for可访问父类对象 -->
<li v-for="(item, index) in items">
{{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
<!-- 结果:
Parent - 0 - Foo
Parent - 1 - Bar
-->
<!-- v-for第二个参数默认情况下表示当前项的位置索引 -->
<div v-for="(value, index) in object">内容:{{ value}},位置:{{ index }}</div>
<!-- v-for也可以自定义第二个参数标识属性名,第三个参数表示位置索引 -->
<div v-for="(value, name, index) in object">内容:{{value}},名称{{ name }},位置:{{ index }}</div>
...
data() {
return {
parentMessage: 'Parent',
items: [{ message: 'Foo' }, { message: 'Bar' }]
}
}
2)v-for
+Key
的示例:
v-for
的默认方式是尝试就地更新元素而不移动它们。要强制其重新排序元素,你需要用特殊 attributekey
来提供一个排序提示:
<div v-for="item in items" :key="item.id">{{ item.text }}</div>
注:key
绑定的值期望是一个基础类型的值,例如字符串或 number 类型。不要用对象作为 v-for
的 key。
3)template上使用v-for
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider" role="presentation"></li>
</template>
</ul>
4)在自定义组件上使用v-for
<MyComponent
v-for="(item, index) in items"
:item="item"
:index="index"
:key="item.id"
/>
但是这样写对象item
不会传递给“自定义组件”,需要使用props
将对象传递给“自定义组件”,见Todo List 的例子。
5)v-for
创建的数组的变化侦测
Vue 能够侦听响应式数组的变更方法,并在它们被调用时触发相关的更新。这些变更方法包括:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
后补(https://cn.vuejs.org/guide/essentials/list.html)
9、v-on
监听 DOM 事件
<a v-on:click="doSomething"> ... </a>
<!-- 简写为@字符 -->
<a @click="doSomething"> ... </a>
1)写法一:内联事件处理器
<!-- 示例一:简单示例 -->
<button @click="count++">Add 1</button>
<p>Count is: {{ count }}</p>
<!-- 示例二:使用特殊的 $event 变量 -->
<button @click="warn('Form cannot be submitted yet.', $event)">
Submit
</button>
<!-- 示例三:使用内联箭头函数 -->
<button @click="(event) => warn('Form cannot be submitted yet.', event)">
Submit
</button>
data() {
return {
count: 0
}
}
methods: {
warn(message, event) {
// 这里可以访问 DOM 原生事件
if (event) {
event.preventDefault()
}
alert(message)
}
}
2)写法二:方法事件处理器
<!-- 示例一:无参写法;`greet` 是定义过的方法名 -->
<button @click="greet">Greet</button>
<!-- 示例一:有参写法 -->
<button @click="say('hello')">Say hello</button>
data() {
return {
name: 'Vue.js'
}
},
methods: {
greet(event) { // 没有类型标注时,这个 event 参数会隐式地标注为 any 类型;显式转化写法为 greet(event: Event) { }
// 方法中的 `this` 指向当前活跃的组件实例
alert(`Hello ${this.name}!`)
// `event` 是 DOM 原生事件
if (event) {
alert(event.target.tagName)
},
say(message) {
alert(message)
}
}
}
3)事件修饰符
后补(https://cn.vuejs.org/guide/essentials/event-handling.html#accessing-event-argument-in-inline-handlers)
4)按键修饰符
后补
5)鼠标按键修饰符
后补
10、v-slot
组件中的占位属性(用于声明具名插槽或是期望接收 props 的作用域插槽)
在某些场景中,我们可能想要为子组件传递一些模板片段,让子组件在它们的组件中渲染这些片段。以下为示例
App.vue
<script>
import FancyButton from './FancyButton.vue'
import AwesomeIcon from './AwesomeIcon.vue'
export default {
components: { FancyButton, AwesomeIcon }
}
</script>
<template>
<FancyButton>
Click me
</FancyButton>
<FancyButton>
<span style="color:red">Click me! </span> <!-- 赋值到slot占位区域 -->
<AwesomeIcon />
</FancyButton>
</template>
FancyButton.vue
<template>
<button class="fancy-btn">
<!-- slot占位 -->
<slot/>
</button>
</template>
<style>
.fancy-btn {
color: #fff;
background: linear-gradient(315deg, #42d392 25%, #647eff);
border: none;
padding: 5px 10px;
margin: 5px;
border-radius: 8px;
cursor: pointer;
}
</style>
AwesomeIcon.vue
<!-- using an emoji just for demo purposes -->
<template>❤️</template>
v-slot
详细介绍见:https://cn.vuejs.org/guide/components/slots.html
11、v-once
仅渲染元素和组件一次
<!-- 单个元素 -->
<span v-once>This will never change: {{msg}}</span>
<!-- 带有子元素的元素 -->
<div v-once>
<h1>comment</h1>
<p>{{msg}}</p>
</div>
<!-- 组件 -->
<MyComponent v-once :comment="msg" />
<!-- `v-for` 指令 -->
<ul>
<li v-for="i in list" v-once>{{i}}</li>
</ul>
12、v-memo
当值与期望的值(或上次的值)不一样时渲染
<!-- 示例1 :[valueA];当组件重新渲染的时候,如果valueA都维持不变,那么对这个<div>以及它的所有子节点的更新都将被跳过。-->
<div v-memo="[valueA]">
...
</div>
<!-- 示例2 :[valueA, valueB];如果 valueA 和 valueB 都保持不变,这个 <div> 及其子项的所有更新都将被跳过-->
<div v-memo="[valueA, valueB]">
...
</div>
<!-- 示例3:item.id === selected;下为“与 v-for 一起使用,有助于渲染海量 v-for 列表 (长度超过 1000 的情况)” -->
<div v-for="item in list" :key="item.id" v-memo="[item.id === selected]">
<p>ID: {{ item.id }} - selected: {{ item.id === selected }}</p>
<p>...more child nodes</p>
</div>
13、v-cloak
隐藏尚未编译的 DOM 模板
解决的Bug:当使用直接在 DOM 中书写的模板时,可能会出现一种叫做“未编译模板闪现”的情况:用户可能先看到的是还没编译完成的双大括号标签,直到挂载的组件将它们替换为实际渲染的内容。
解决的对策:使用v-cloak
,v-cloak
会保留在所绑定的元素上,直到相关组件实例被挂载后才移除。配合像 [v-cloak] { display: none }
这样的 CSS 规则,它可以在组件编译完毕前隐藏原始模板。
示例:
<div v-cloak>{{ message }}</div>
[v-cloak] {
display: none;
}
14、自定义指令directives
(后看)
当在组件上使用自定义指令时,它会始终应用于组件的根节点。当应用到一个多根组件时,指令将会被忽略且抛出一个警告。和 attribute 不同,指令不能通过 v-bind="$attrs"
来传递给一个不同的元素。总的来说,不推荐在组件上使用自定义指令。
1)自定义指令(示例:当一个 input 元素被 Vue 插入到 DOM 中后,它会被自动聚焦)
<input v-focus />
...
const focus = { // 指令对象
mounted: (el) => el.focus()
}
export default {
directives: { // 在这里面自定义指令
// 在模板中启用 v-focus
focus
}
}
2)自定义全局指令
const app = createApp({})
// 使 v-focus 在所有组件中都可用
app.directive('focus', {
/* ... */
})
3)指令中使用钩子
// el: 指令绑定到的元素。这可以用于直接操作 DOM。
// binding:一个对象,包含以下属性
// value:传递给指令的值。例如在 v-my-directive="1 + 1" 中,值是 2。
// oldValue:之前的值,仅在 beforeUpdate 和 updated 中可用。无论值是否更改,它都可用。
// arg:传递给指令的参数 (如果有的话)。例如在 v-my-directive:foo 中,参数是 "foo"。
// modifiers:一个包含修饰符的对象 (如果有的话)。例如在 v-my-directive.foo.bar 中,修饰符对象是 { foo: true, bar: true }。
// instance:使用该指令的组件实例。
// dir:指令的定义对象。
// vnode:代表绑定元素的底层 VNode。
// prevVnode:之前的渲染中代表指令所绑定元素的 VNode。仅在 beforeUpdate 和 updated 钩子中可用。
const myDirective = {
// 在绑定元素的 attribute 前
// 或事件监听器应用前调用
created(el, binding, vnode, prevVnode) {
// 下面会介绍各个参数的细节
},
// 在元素被插入到 DOM 前调用
beforeMount(el, binding, vnode, prevVnode) {},
// 在绑定元素的父组件
// 及他自己的所有子节点都挂载完成后调用
mounted(el, binding, vnode, prevVnode) {},
// 绑定元素的父组件更新前调用
beforeUpdate(el, binding, vnode, prevVnode) {},
// 在绑定元素的父组件
// 及他自己的所有子节点都更新后调用
updated(el, binding, vnode, prevVnode) {},
// 绑定元素的父组件卸载前调用
beforeUnmount(el, binding, vnode, prevVnode) {},
// 绑定元素的父组件卸载后调用
unmounted(el, binding, vnode, prevVnode) {}
}
4)简化调用钩子
对于自定义指令来说,一个很常见的情况是仅仅需要在 mounted
和 updated
上实现相同的行为,除此之外并不需要其他钩子。这种情况下我们可以直接用一个函数来定义指令,如下所示:
<div v-color="color"></div>
app.directive('color', (el, binding) => {
// 这会在 `mounted` 和 `updated` 时都调用
el.style.color = binding.value
})
5)使用对象字面量
如果你的指令需要多个值,你可以向它传递一个 JavaScript 对象字面量(JavaScript 表达式)。
<div v-demo="{ color: 'white', text: 'hello!' }"></div>
app.directive('demo', (el, binding) => {
console.log(binding.value.color) // => "white"
console.log(binding.value.text) // => "hello!"
})
15、一些指令的联合使用注意事项:
1)v-if
vs. v-show
v-if
是“真实的”按条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建。
v-if
也是惰性的:如果在初次渲染时条件值为 false,则不会做任何事。条件区块只有当条件首次变为 true 时才被渲染。
相比之下,v-show
简单许多,元素无论初始条件如何,始终会被渲染,只有 CSS display
属性会被切换。
总的来说,v-if
有更高的切换开销,而 v-show
有更高的初始渲染开销。因此,如果需要频繁切换,则使用 v-show
较好;如果在运行时绑定条件很少改变,则 v-if
会更合适。
2)v-if
和 v-for
当 v-if
和 v-for
同时存在于一个元素上的时候,v-if
会首先被执行。这意味着 v-if
的条件将无法访问到 v-for
作用域内定义的变量别名;在外新包装一层 <template>
再在其上使用 v-for
可以解决这个问题 (这也更加明显易读):
<template v-for="todo in todos">
<li v-if="!todo.isComplete">
{{ todo.name }}
</li>
</template>
16、组件间传值(见Vue3 学习笔记(九)——Vue组件的使用)
1)props
:子组件通过props
属性监听父元素传过来的数据;子组件通过events
给父组件发送消息;
2)$emit()
:子组件通过$emit
调用父组件的方法并传递数据;
3)events
:子组件通过events
声明需要抛出的方法或变量;
四、DOM 模板解析注意事项
1、大小写区分
HTML 标签和属性名称是不分大小写的,所以浏览器会把任何大写的字符解释为小写。这意味着当你使用 DOM 内的模板时,无论是 PascalCase 形式的组件名称、camelCase 形式的 prop 名称还是 v-on 的事件名称,都需要转换为相应等价的 kebab-case (短横线连字符) 形式:
原内容:
// JavaScript 中的 camelCase
const BlogPost = {
props: ['postTitle'],
emits: ['updatePost'],
template: `
<h3>{{ postTitle }}</h3>
`
}
解析后:
<!-- HTML 中的 kebab-case -->
<blog-post post-title="hello!" @update-post="onUpdatePost"></blog-post>
2、闭合标签
这是因为 Vue 的模板解析器支持任意标签使用 />
作为标签关闭的标志,如:<MyComponent />
。然而在 DOM 模板中,我们必须显式地写出关闭标签,如:<my-component></my-component>
。这是由于 HTML 只允许一小部分特殊的元素省略其关闭标签,最常见的就是 <input>
和 <img>
。对于其他的元素来说,如果你省略了关闭标签,原生的 HTML 解析器会认为开启的标签永远没有结束,举例如下:
原内容:
<my-component /> <!-- 我们想要在这里关闭标签... -->
<span>hello</span>
解析后:
<my-component>
<span>hello</span>
</my-component> <!-- 但浏览器会在这里关闭标签 -->
3、元素位置限制
某些 HTML 元素对于放在其中的元素类型有限制,例如 <ul>
,<ol>
,<table>
和 <select>
,相应的,某些元素仅在放置于特定元素中时才会显示,例如 <li>
,<tr>
和 <option>
。
<table>
<blog-post-row></blog-post-row>
</table>
自定义的组件 <blog-post-row>
将作为无效的内容被忽略。 可写成下面的样式:
<table>
<tr>
<blog-post-row></blog-post-row>
</tr>
</table>
<!-- 或者 -->
<table>
<tr is="vue:blog-post-row"></tr>
</table>
4、组件名格式
1)组件名官方推荐使用PascalCase命名规则,如:<PascalCase />
;但是,PascalCase 的标签名在 DOM 模板中是不可用的。
2)为了方便,Vue 支持将模板中使用 kebab-case 的标签解析为使用 PascalCase 注册的组件。这意味着一个以 MyComponent
为名注册的组件,在模板中可以通过 <MyComponent>
或 <my-component>
引用。
本文来自博客园,作者:꧁执笔小白꧂,转载请注明原文链接:https://www.cnblogs.com/qq2806933146xiaobai/articles/17330357.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下