跳到主要内容

mustache-Vue编译

Vue 的模板基于 HTML,开发者可以直接在模板中编写 HTML 代码,HTML 解析器能够解析这些代码。

Vue 自己的模板编译系统

在开发过程中,我编写的 template 会被解析成 HTML 字符串,并转换成抽象语法树(AST)。表达式、自定义属性和指令会被转换成虚拟 DOM,通过对比差异生成补丁,最终渲染成真实的 DOM。

虚拟 DOM 的价值

虚拟 DOM 的主要价值在于高效地更新页面。当发现虚拟 DOM 与真实 DOM 之间存在差异时,才会生成补丁并应用到真实 DOM 上,从而优化性能。

<span>Vue</span>;
span.innerHTML = 'Vue';

指令

指令定义了模板渲染的逻辑行为,以下是常用的 Vue 指令及其使用方法。

v-once 指令用于一次性渲染插值内容,绑定的 DOM 元素不会再更新。

v-html 指令用于插入原始 HTML 内容,插值表达式是 JavaScript 表达式,不会对 DOM 进行操作。建议不要使用 v-html 来渲染子模板,而应将子模板放入子组件中。

动态属性名允许属性名根据数据动态改变。

<template>
<div>
<div>
<h1 v-bind:[attr]="tag">{{ title }}</h1>
<h1 v-bind:[null]="title">{{ title }}</h1>
<h1 v-bind:[myAttr]="title">{{ title }}</h1>
<a :[aAttr]="urls[0]" target="_blank">淘宝商城</a>
</div>
<div>
<button @[eventName]="">淘宝</button>
</div>
</div>
</template>

<script>
export default {
data() {
return {
linkIndex: 0,
aAttr: 'href',
eventName: 'click',
attr: 'data-tag',
myAttr: 'data-attr',
tag: 'h1',
title: 'This is my TITLE',
urls: ['https://www.taobao.com', 'https://www.tmall.com', 'https://www.jd.com'],
};
},
};
</script>

在上述示例中:

  • v-bind:[attr]="tag" 动态绑定属性名,属性名由 attr 变量决定,属性值为 tag
  • v-bind:[null]="title" 使用 null 作为属性名,实际不会绑定任何属性。
  • v-bind:[myAttr]="title" 动态绑定自定义属性,属性名由 myAttr 变量决定。
  • :[aAttr]="urls[0]" 动态绑定 href 属性,属性值为 urls 数组的第一个元素。
  • @[eventName]="" 动态绑定事件名,事件名由 eventName 变量决定。

通过动态绑定属性名和事件名,可以根据不同的数据动态调整组件的行为和样式,提高代码的灵活性和可维护性。

组件通信

在 Vue 中,组件之间的通信是通过 props 和事件实现的。父组件通过 props 向子组件传递数据,子组件通过事件向父组件发送消息。这种单向数据流的方式使得组件之间的关系更加清晰和易于维护。

父组件传递数据给子组件

父组件可以通过在子组件标签上添加属性来传递数据。

<template>
<div>
<ChildComponent :message="parentMessage" />
</div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
components: {
ChildComponent,
},
data() {
return {
parentMessage: 'Hello from Parent',
};
},
};
</script>

在子组件中,通过 props 接收父组件传递的数据。

<template>
<div>
{{ message }}
</div>
</template>

<script>
export default {
props: {
message: {
type: String,
required: true,
},
},
};
</script>

子组件向父组件发送事件

子组件可以通过 $emit 方法触发自定义事件,通知父组件执行相应的操作。

<template>
<div>
<button @click="sendMessage">Send Message to Parent</button>
</div>
</template>

<script>
export default {
methods: {
sendMessage() {
this.$emit('message-sent', 'Hello from Child');
},
},
};
</script>

父组件监听子组件的自定义事件,并处理传递的数据。

<template>
<div>
<ChildComponent @message-sent="handleMessage" />
</div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
components: {
ChildComponent,
},
methods: {
handleMessage(message) {
console.log(message);
},
},
};
</script>

通过 props 和事件,Vue 实现了父子组件之间的高效通信,确保数据流动的可预测性和组件的独立性。

计算属性和侦听器

计算属性和侦听器是 Vue 中处理数据变化的两种重要方式。计算属性用于基于已有数据计算出新的数据,而侦听器用于在数据变化时执行异步或开销较大的操作。

计算属性

计算属性基于它们的依赖进行缓存,只有相关依赖发生变化时,才会重新计算。这使得计算属性在性能上优于方法调用。

<template>
<div>
<p>Original Message: {{ message }}</p>
<p>Reversed Message: {{ reversedMessage }}</p>
</div>
</template>

<script>
export default {
data() {
return {
message: 'Hello Vue!',
};
},
computed: {
reversedMessage() {
return this.message.split('').reverse().join('');
},
},
};
</script>

在上述示例中,reversedMessage 是一个计算属性,它依赖于 message。当 message 发生变化时,reversedMessage 会自动更新。

侦听器

侦听器用于观察 Vue 实例上的数据变动,当数据变化时执行相应的回调函数。适用于需要在数据变化时执行异步操作或开销较大的操作。

<template>
<div>
<input v-model="searchQuery" placeholder="Search..." />
<ul>
<li v-for="item in filteredItems" :key="item.id">{{ item.name }}</li>
</ul>
</div>
</template>

<script>
export default {
data() {
return {
searchQuery: '',
items: [
{ id: 1, name: 'Apple' },
{ id: 2, name: 'Banana' },
{ id: 3, name: 'Cherry' },
],
filteredItems: [],
};
},
watch: {
searchQuery(newQuery) {
this.filteredItems = this.items.filter((item) => item.name.toLowerCase().includes(newQuery.toLowerCase()));
},
},
created() {
this.filteredItems = this.items;
},
};
</script>

在上述示例中,当 searchQuery 变化时,侦听器会过滤 items 并更新 filteredItems,从而动态显示匹配的结果。

通过合理使用计算属性和侦听器,可以提高应用的响应速度和用户体验。

生命周期钩子

Vue 实例在创建过程中会经历多个生命周期阶段,每个阶段都有对应的生命周期钩子,允许开发者在特定时机执行代码。

常用的生命周期钩子

  • created: 实例创建完成后被调用,此时数据已设置,事件已配置,但 DOM 尚未挂载。
  • mounted: 实例挂载到 DOM 后被调用,此时可以访问到 DOM 元素。
  • updated: 数据更新导致虚拟 DOM 重新渲染和打补丁后调用。
  • destroyed: 实例销毁后调用,适合进行清理工作。
<template>
<div>
<p>Current Time: {{ currentTime }}</p>
</div>
</template>

<script>
export default {
data() {
return {
currentTime: '',
};
},
created() {
console.log('Component is created');
this.currentTime = new Date().toLocaleTimeString();
},
mounted() {
console.log('Component is mounted');
this.timer = setInterval(() => {
this.currentTime = new Date().toLocaleTimeString();
}, 1000);
},
updated() {
console.log('Component is updated');
},
destroyed() {
console.log('Component is destroyed');
clearInterval(this.timer);
},
};
</script>

在上述示例中:

  • created 钩子用于初始化数据。
  • mounted 钩子开始一个定时器,每秒更新一次 currentTime
  • updated 钩子在数据更新后记录日志。
  • destroyed 钩子在组件销毁时清理定时器。

了解和合理利用生命周期钩子,可以帮助开发者更好地控制组件的行为和资源管理。

结语

通过本文的介绍,您已经了解了 Vue 的模板语法、指令、组件通信、计算属性与侦听器以及生命周期钩子等核心概念。这些知识点是构建高效、可维护 Vue 应用的基础。建议在实际项目中多加练习和应用,以深入掌握 Vue 的强大功能。