目录

Vue.js 模板语法全解析:从基础到实战应用

引言

在 Vue.js 的开发体系中,模板语法是构建用户界面的核心要素,它让开发者能够高效地将数据与 DOM 进行绑定,实现动态交互效果。通过对《Vue.js 快速入门实战》中关于 Vue 项目部署章节(实际围绕 Vue 模板语法展开)的深入研读,我们将全面剖析 Vue 项目结构、应用程序实例、生命周期、插值、指令以及自定义指令等关键内容,并通过实战案例加深理解。

1. Vue 项目详解

项目目录结构

以常见的**vite - app**项目为例,其目录结构清晰且分工明确,各部分协同支撑起整个 Vue 项目的开发与运行。

  • public 目录 :如同项目的公共资源库 ,存放那些无需经过构建处理的文件,如index.htmlfavicon.ico等。其中**index.html** 作为项目的入口页面,为整个 Vue 应用提供了基础的 HTML 结构,所有 Vue 组件最终都会被挂载到该页面的特定元素上。
  • src 目录 :这是项目源代码的核心存储地,是开发者编写业务逻辑、组件、样式等代码的主要区域。
    • assets 子目录 :专门用于存放静态资源 ,如图片、字体、音频等。例如,项目中用到的产品图片可以存放在此目录下,在组件中通过相对路径引用,如<img src="@/assets/product.jpg" alt="产品图片">,这里的@是 Vite 等构建工具设置的指向src目录的别名,方便开发者引用资源。
    • components 子目录 :是组件的 "家园",各种可复用的 Vue 组件 都在此定义和存放。比如一个用于展示商品列表的ProductList.vue组件,包含了商品列表的展示逻辑、样式以及与用户交互的功能。在其他组件中可通过import ProductList from '@/components/ProductList.vue'导入并使用。
    • App.vue :作为项目的入口组件 ,它是整个 Vue 应用的根组件 ,负责构建应用的整体结构,通常会引入并组合其他子组件,形成完整的用户界面。例如,在App.vue中可能会引入ProductList.vueHeader.vue等组件,通过<template>标签将它们组合在一起展示给用户。
  • node_modules 目录 :这个目录由包管理工具 (如 npm、yarn、pnpm)自动生成,用于存放项目依赖的第三方包。当在项目中执行npm install安装axios(用于发起 HTTP 请求的库)时,axios及其依赖的其他包就会被下载并存储在node_modules目录下。项目运行时,构建工具会从这里读取相关包的代码并进行打包处理。

应用程序实例

Vue 项目本质上是一个单页面应用程序(SPA) ,每个 Vue 应用都有一个核心的应用程序实例。通过 Vue 提供的**createApp()** 方法可以轻松创建这个实例。在典型的main.ts文件(如果是 TypeScript 项目,JavaScript 项目则是main.js)中,代码const app = createApp(App),这里的App是前面提到的App.vue组件,它作为参数传递给createApp()方法,从而创建了一个以App.vue为根组件的 Vue 应用实例。

创建实例后,还需要指定一个 DOM 元素作为挂载点 ,让 Vue 应用能够在网页中展示。使用**app.mount('#app')语句,它会在 HTML 页面中找到idapp的元素,并将 Vue 应用挂载到该元素上。例如,在public/index.html中存在<div id="app"></div>,Vue 应用的所有内容就会渲染在这个div元素内部。此时,Vue 的数据双向绑定机制开始生效,组件中的数据变化会实时反映在 DOM 上,用户对 DOM 的操作也能同步更新到数据中。比如在App.vue组件中有一个数据变量message,在模板中通过{``{ message }}** 进行插值显示,当message的值发生变化时,页面上显示的内容也会随之改变。

2. Vue 生命周期

生命周期图示

Vue 组件从诞生到销毁的过程被称为生命周期,通过一张详细的生命周期图,可以清晰地看到其完整的生命周期流程。图中展示了从**beforeCreate开始** ,到**unmounted结束** 的各个阶段,其中**beforeCreatecreatedbeforeMountmountedbeforeUpdateupdatedbeforeUnmountunmounted**等阶段尤为关键,这些阶段对应的阴影框标注的就是生命周期钩子函数。这些钩子函数为开发者提供了在组件不同生命周期阶段执行自定义逻辑的机会。

钩子函数详解及示例

  • beforeCreate :在 Vue 实例初始化之前被调用,此时组件的data变量还未被初始化为响应式变量,组件的methodscomputed等属性也尚未被创建。例如,在一个自定义组件MyComponent.vue中定义该钩子函数:
javascript 复制代码
export default {
  beforeCreate() {
    console.log('beforeCreate()');
  }
}

在组件初始化 时,控制台会输出**beforeCreate()** 。这个阶段通常用于一些初始化操作,如在这个阶段设置一些全局的配置信息,但由于此时无法访问组件的datamethods,所以能做的操作相对有限。

  • created :当 Vue 实例初始化完成后,该钩子函数被调用。此时,data已经变成响应式变量,methods也已被创建,开发者可以访问组件的datamethods。在实际开发中,这个阶段常用于发起数据请求来获取初始数据。例如:
javascript 复制代码
export default {
  data() {
    return {
      userInfo: null
    };
  },
  created() {
    // 假设这里使用axios发起请求获取用户信息
    axios.get('/api/userInfo').then(response => {
      this.userInfo = response.data;
    });
  }
}
  • mounted:组件挂载到 DOM 并渲染完成后调用此钩子函数。此时,组件的所有内容都已在页面中呈现,开发者可以访问组件的全部内容,包括 DOM 元素。例如,在一个需要操作 DOM 元素的场景中:
javascript 复制代码
export default {
  mounted() {
    const element = document.getElementById('myElement');
    if (element) {
      element.style.color ='red';
    }
    console.log('mounted()');
  }
}

在模板中存在<div id="myElement">这是一个元素</div>,当组件挂载完成 后,该元素的文本颜色会变为红色,同时控制台输出**mounted()**。


  • beforeUpdate:当组件的数据发生变化后,DOM 重新渲染之前调用此钩子函数。在这个阶段,数据已经更新,但 DOM 还未更新,开发者可以在此进行一些数据更新前的准备工作,如记录数据变化前的状态。例如:
javascript 复制代码
export default {
  data() {
    return {
      count: 0
    };
  },
  methods: {
    increment() {
      this.count++;
    }
  },
  beforeUpdate() {
    console.log('数据即将更新,当前count值为', this.count);
  }
}

当调用increment方法使count值增加时,控制台会输出数据更新前count的值。


  • updated:DOM 重新渲染完成后调用此钩子函数。在这个阶段,数据和 DOM 都已经更新完成,开发者可以在此对更新后的 DOM 进行操作。例如:
javascript 复制代码
export default {
  data() {
    return {
      text: '初始文本'
    };
  },
  methods: {
    changeText() {
      this.text = '新的文本';
    }
  },
  updated() {
    const updatedElement = document.querySelector('span');
    if (updatedElement) {
      console.log('更新后的DOM元素文本为', updatedElement.textContent);
    }
  }
}

在模板中有<span>{``{ text }}</span>,当调用changeText方法后,updated钩子函数会输出更新后 DOM 元素的文本内容。


  • activated :当被keep - alive缓存的组件被激活时调用。keep - alive是 Vue 提供的一个组件,用于缓存组件实例,避免组件重复创建和销毁。例如,在一个多页面切换的应用中,有一个PageComponent组件被keep - alive包裹,当用户再次切换到该页面时,activated钩子函数会被调用。
javascript 复制代码
export default {
  activated() {
    console.log('组件被激活');
  }
}

  • deactivated :当被keep - alive缓存的组件失活时调用。例如,当用户从被keep - alive缓存的PageComponent组件所在页面切换到其他页面时,deactivated钩子函数会被触发。
javascript 复制代码
export default {
  deactivated() {
    console.log('组件失活');
  }
}

3. Vue 的插值

Mustache 语法插值

在 Vue 的 HTML 模板中,Mustache 语法**(双大括号)** 是实现数据绑定的常用方式。

例如,在一个组件的模板中存在{``{ message }},这里的message是组件实例中的一个数据变量。假设在组件的data选项中定义了message: 'Hello, Vue!',那么在页面渲染时,{``{ message }}会被自动替换为Hello, Vue!。并且,当message的值发生变化时,插值的内容也会实时更新。

比如在组件的methods中有一个方法updateMessage

javascript 复制代码
export default {
  data() {
    return {
      message: 'Hello, Vue!'
    };
  },
  methods: {
    updateMessage() {
      this.message = 'New message';
    }
  }
}

当调用updateMessage方法后,页面上原本显示的Hello, Vue!会立即变为New message

HTML 文本插值

当需要在模板中渲染包含 HTML 标签的文本 时,如果直接使用双大括号绑定,这些 HTML 标签会被当作文本原样显示。

例如,有一个变量htmlMessage = '<p>这是一段HTML文本</p>',在模板中使用{``{ htmlMessage }},页面上会显示<p>这是一段HTML文本</p>,而不是将其渲染为一个段落。

为了正确渲染 HTML 内容,需要使用**v - html指令**。

<span v - html="htmlMessage"></span>,此时页面上会正确显示一个包含 "这是一段 HTML 文本" 的段落。但使用v - html时要格外注意安全问题,因为它可能会引入跨站脚本攻击(XSS )风险。如果htmlMessage是用户输入的内容且未经过严格过滤,恶意用户可能会输入恶意脚本代码,如<script>alert('恶意代码')</script>,一旦渲染,就会在页面上执行恶意脚本,所以在使用v - html渲染用户输入内容时,一定要进行严格的输入验证和过滤。

4. Vue 的指令

内置指令

v - text

该指令用于更新 DOM 元素的textContent属性。

例如,在模板中有<span v - text="textMessage"></span>,假设在组件的data中定义了textMessage = '这是通过v - text指令设置的文本',那么在页面渲染时,<span>标签内的文本会被设置为这是通过v - text指令设置的文本,其效果等同于在 JavaScript 中执行span.textContent = '这是通过v - text指令设置的文本'

与 Mustache 语法插值不同的是,v - text不会对插值内容进行解析,只是单纯地设置textContent


v - htm

用于更新 DOM 元素的**innerHTML属性** ,能够将包含 HTML 标签的字符串正确渲染为 HTML 结构。例如<div v - html="richHtml"></div>,其中richHtml = '<h1>标题</h1><p>段落内容</p>',在页面上会显示一个包含标题和段落的 HTML 结构。但如前文所述,使用时要注意防止 XSS 攻击,避免渲染恶意 HTML 代码。

v - show

通过切换元素的display CSS 属性来控制元素的显示或隐藏

例如<div v - show="showValue">这是一个根据v - show显示或隐藏的元素</div>,在组件的data中定义showValue = true时,该div元素正常显示;当showValue = false时,元素的display属性会被设置为none,从而在页面上隐藏。

v - if不同,v - show只是通过 CSS 控制元素的显示状态,元素始终存在于 DOM 中,而v - if在条件为false时,元素根本不会被创建。

v - if

根据传入的布尔值判断是否渲染当前元素。

例如<div v - if="isLoggedIn">欢迎登录</div>,当组件的dataisLoggedIn = true时,<div>元素会被渲染到页面上;当isLoggedIn = false时,该<div>元素及其内部内容不会被创建,在 DOM 中不存在。

这种方式适用于在某些条件下完全不需要渲染某个元素的场景,相比v - show,它不会在 DOM 中保留元素,因此在性能上更优,尤其是在条件判断频繁切换且元素结构复杂的情况下。

v - elsev - else - if

这两个指令必须与v - ifv - else - if连用,用于实现复杂的逻辑判断和元素渲染。例如:

html 复制代码
<div v - if="score >= 90">优秀</div>
<div v - else - if="score >= 60">及格</div>
<div v - else>不及格</div>

在组件的data中定义score = 80时,页面上会显示 "及格"。

v - for

主要用于遍历数组、对象 等数据结构来渲染多个元素

例如<div v - for="item in items">{``{ item }}</div>,假设在组件的data中定义items = ['苹果', '香蕉', '橘子'],页面上会渲染出三个div,分别显示 "苹果""香蕉""橘子"。

此外,还可以获取遍历的索引或对象的键,如v - for="(item, index) in items",在模板中可以通过index获取当前项的索引;对于对象遍历v - for="(value, key) in object",可以通过key获取对象的键。

v - pre

使用该指令可以跳过这个元素和它的子元素的编译过程,直接显示原始的 Mustache 标签。

例如<span v - pre>{``{ message }}</span>,页面上会直接显示{``{ message }},而不会将其解析为数据绑定进行渲染,常用于展示一些不需要 Vue 编译的纯文本内容,如一些包含特殊占位符的模板示例展示。

v - once

只渲染元素和组件一次 ,之后即使其内部绑定的数据发生变动,也不会重新渲染

例如<div v - once>{``{ initialValue }}</div>,在组件初始化时,initialValue的值会被渲染到div中,后续initialValue的值无论如何变化,div中的内容都不会更新,这种方式适用于一些数据在初始渲染后不会再改变的场景,能提高一定的性能。

v - cloak

通常与 CSS 规则**[v - cloak] { display: none; }一起使用** 。在 Vue 组件实例加载过程中,未编译的 Mustache 标签可能会短暂显示在页面上,影响用户体验。使用v - cloak指令后,在组件实例准备好之前,带有v - cloak指令的元素会根据 CSS 规则隐藏,当 Vue 完成编译,v - cloak指令会从 DOM 中移除,元素正常显示。例如<div v - cloak>{``{ message }}</div>,在 Vue 加载过程中,该div元素是隐藏的,加载完成后,div中正确显示message的值。

v - on

用于绑定事件监听器 。例如<button v - on:click="onClick">点击</button>,在组件的methods中定义onClick方法,当用户点击按钮时,onClick方法会被调用。

v - on有简写形式@,上述代码可简写为<button @click="onClick">点击</button>

此外,v - on 还支持修饰符,如**.stop修饰符**,<button @click.stop="onClick">点击</button>,当按钮被点击时,会调用**event.stopPropagation()** 方法,阻止事件冒泡;**.prevent修饰符,<a @click.prevent="handleClick" href="#">链接</a>,点击链接时,会调用event.preventDefault()**方法,阻止链接的默认跳转行为。

v - bind

用于动态绑定 一个或多个 DOM 元素属性 。例如<input v - bind:placeholder="placeholderMessage" :id="bindId">,这里v - bind:placeholderplaceholderMessage变量的值绑定到输入框的placeholder属性上,

**:idv - bind:id**的简写形式,将bindId变量的值绑定到输入框的id属性上。假设在组件的data中定义placeholderMessage = '请输入内容'bindId = 'input - 1',则在页面上输入框的placeholder属性值为 "请输入内容",id属性值为 "input - 1"。

v-model

v-model是 Vue 中实现表单双向绑定的强大指令,它极大地简化了表单元素与 Vue 实例数据之间的同步操作。其核心特性是能够根据表单控件的类型,自动选择最合适的更新方式来保持数据的一致性。

对于<input>元素,当使用v-model指令时,输入框的值会与 Vue 实例中的对应数据实时同步

例如,在模板中有<input v-model="userInput">,在 Vue 组件的data选项中定义了userInput: ''。当用户在输入框中输入内容时,userInput的值会立即更新;反之,当通过 JavaScript 代码修改userInput的值时,输入框中的显示内容也会相应改变。这一过程无需开发者手动监听input事件并更新数据,v-model会自动处理。

<textarea>元素上,v-model同样适用。

<textarea v-model="textAreaContent"></textarea>,假设textAreaContent初始值为'请输入一些文本',用户在文本区域内进行的任何编辑操作都会同步更新textAreaContent,并且当textAreaContent在其他地方被修改时,文本区域的显示内容也会更新。

对于<select>元素,v-model用于绑定选中的选项。例如:

html 复制代码
<select v-model="selectedOption">
    <option value="option1">选项1</option>
    <option value="option2">选项2</option>
    <option value="option3">选项3</option>
</select>

在组件的data中定义selectedOption: 'option1',页面加载时,select元素会默认选中值为option1的选项。当用户选择其他选项时,selectedOption的值会自动更新为所选选项的值;

若在 JavaScript 代码中修改selectedOption的值,select元素也会自动切换到对应的选项。

此外,v-model还支持修饰符 ,如.lazy修饰符。默认情况下,v-modelinput事件触发时更新数据,但使用.lazy修饰符后,会在change事件触发时更新数据。

例如<input v-model.lazy="userInput">,这样只有当用户完成输入并失去焦点(或按下回车键)时,userInput才会更新,适用于一些对实时性要求不高、希望减少数据更新频率的场景。

v-slot

v-slot主要用于在组件中提供具名插槽 或接收**prop的插槽**,它为组件的内容分发提供了更灵活的方式。

具名插槽允许在一个组件的模板中定义多个插槽,并通过名称来区分。

例如,在一个BaseLayout组件中,可能有headercontentfooter三个不同的插槽:

html 复制代码
<!-- BaseLayout.vue -->
<template>
    <div>
        <slot name="header"></slot>
        <slot name="content"></slot>
        <slot name="footer"></slot>
    </div>
</template>

在使用**BaseLayout组件**时,可以这样填充这些具名插槽:

html 复制代码
<BaseLayout>
    <template v-slot:header>
        <h1>页面标题</h1>
    </template>
    <template v-slot:content>
        <p>这是页面的主要内容。</p>
    </template>
    <template v-slot:footer>
        <p>版权所有 © 2024</p>
    </template>
</BaseLayout>

v-slot还可以接收prop ,用于在插槽内容中动态传递数据

比如有一个ListComponent组件,它渲染一个列表,并允许在每个列表项的插槽中接收额外的信息:

html 复制代码
<!-- ListComponent.vue -->
<template>
    <ul>
        <li v-for="(item, index) in listItems" :key="index">
            {{ item.text }}
            <slot :itemData="item" name="extraInfo"></slot>
        </li>
    </ul>
</template>
<script>
export default {
    data() {
        return {
            listItems: [
                { text: '项目1', extra: '额外信息1' },
                { text: '项目2', extra: '额外信息2' }
            ]
        };
    }
};
</script>

在使用**ListComponent组件** 时,可以这样利用接收prop的插槽:

html 复制代码
<ListComponent>
    <template v-slot:extraInfo="{ itemData }">
        <span style="color: blue;">{{ itemData.extra }}</span>
    </template>
</ListComponent>

这样,每个列表项的extra信息就会以蓝色文本显示在插槽位置。

自定义指令

全局自定义指令

全局自定义指令可以在整个 Vue 应用中使用。在main.ts文件中,通过app.directive('指令名', { /* 指令定义对象 */ })来注册。例如:

TypeScript 复制代码
// main.ts
import { createApp } from 'vue';
import App from './App.vue';

const app = createApp(App);

app.directive('globalText', {
    mounted(el) {
        el.innerHTML = '全局注册自定义指令';
    }
});

app.mount('#app');

在模板中,任何组件都可以使用这个全局自定义指令:

复制代码
<p v-globalText></p>

当页面渲染到这个<p>元素时,其内容会被替换为 "全局注册自定义指令"。全局自定义指令常用于一些通用的 DOM 操作场景,比如添加特定的样式、行为等,且在多个组件中都可能用到的情况。

局部自定义指令

局部自定义指令是在组件内部通过directives选项进行注册的,只在当前组件及其子组件中生效。例如,在一个MyComponent.vue组件中:

html 复制代码
<template>
    <div>
        <p v-componentText></p>
    </div>
</template>
<script>
export default {
    directives: {
        componentText: {
            mounted(el) {
                el.innerHTML = '组件内注册自定义指令';
            }
        }
    }
};
</script>

在**MyComponent.vue** 组件的模板中,<p>元素使用v-componentText指令,当该组件渲染时,<p>元素的内容会被设置为 "组件内注册自定义指令"。局部自定义指令适用于仅在特定组件中使用的一些特殊 DOM 操作逻辑,避免了全局指令可能带来的命名冲突等问题,同时也增强了组件的封装性。

实战:制作一个便签程序

便签程序是一个很好的 Vue.js 模板语法实践案例,它综合运用了前面所学的诸多知识。

首先,在 HTML 结构上,需要一个输入框用于记录信息。通过v-model指令将输入框的值与 Vue 实例中的数据进行双向绑定。例如

html 复制代码
<input v-model="newNote" placeholder="输入便签内容">

在 Vue 组件的data选项中定义newNote: '',这样用户在输入框中输入的内容会实时反映在newNote变量中。

还需要一个按钮来生成笔记。通过**v-on指令绑定点击事件** ,将newNote添加到笔记列表中。假设在组件的methods中有一个addNote方法:

html 复制代码
<button @click="addNote">添加便签</button>
javascript 复制代码
export default {
    data() {
        return {
            newNote: '',
            notes: []
        };
    },
    methods: {
        addNote() {
            if (this.newNote.trim()!== '') {
                this.notes.push(this.newNote);
                this.newNote = '';
            }
        }
    }
};

对于展示笔记的列表,使用v-for指令遍历notes数组,将每一条笔记渲染出来:

html 复制代码
<ul>
    <li v-for="(note, index) in notes" :key="index">
        {{ note }}
        <button @click="deleteNote(index)">删除</button>
    </li>
</ul>

这里的deleteNote方法用于从notes数组中删除指定索引的笔记:

javascript 复制代码
methods: {
    // 其他方法...
    deleteNote(index) {
        this.notes.splice(index, 1);
    }
}

通过这样一个便签程序的实现,读者可以更深入地理解 Vue.js 模板语法中的数据绑定(如v-model)、事件监听(如v-on)、列表渲染(如v-for)等知识在实际项目中的应用,将理论知识与实践相结合,提升对 Vue.js 开发的掌握程度。

总结

本文深入探讨了 Vue.js 模板语法相关的各个关键方面。

从项目的基础架构,如清晰的目录结构以及应用程序实例的创建与挂载,为 Vue 项目搭建起稳固的基石。Vue 组件生命周期钩子函数 为开发者提供了在不同阶段执行特定逻辑的时机,极大地增强了开发的灵活性。插值与指令 是 Vue.js 模板语法的核心亮点,Mustache 语法插值简洁直观地实现数据绑定,各类内置指令丰富了对 DOM 元素的操作手段,自定义指令又为特定需求提供了定制化解决方案。

通过便签程序这一实战案例,更是将所学的 Vue.js 模板语法知识融会贯通,让读者切实体会到如何运用这些知识来构建一个具有实际功能的应用程序。

总之,熟练掌握这些 Vue.js 模板语法内容,对于高效开发优质的 Vue 项目具有至关重要的意义,能够帮助开发者更好地实现复杂的用户界面交互逻辑,提升开发效率与应用质量。

喜欢就点点赞和关注一起进步吧

本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
她的双马尾6 分钟前
前端性能优化
前端·nginx·webpack·性能优化
回村中年7 分钟前
rudux中间件
开发语言·javascript·中间件
luojiaao16 分钟前
【Python Web全栈开发】通过nginx实现http代理
前端·nginx·http
weixin_4435669817 分钟前
http 和 https
前端
Heisenberg~31 分钟前
C++ 继承:面向对象编程的核心概念(二)
开发语言·javascript·c++
万维组态21 小时前
可视化web组态开发工具
前端·后端·物联网·前端框架·html5
前端Hardy1 小时前
HTML&CSS:超实用的登录页面(建议收藏)
javascript·css·html
梦兮林夕1 小时前
17 国际化与 Next.js 中的国际化实现
前端·react.js·next.js
知识分享小能手1 小时前
CSS3学习教程,从入门到精通,CSS3 动画美化页面知识点及案例代码(19)
前端·javascript·css·学习·html·css3·html5
_jiang1 小时前
AI 生成的 Markdown 无法直接分享怎么办?写一个 Markdown to 在线 HTML 链接转换器
前端·ai编程·vitepress