当前位置: 首页 > news >正文

【Vue】模板语法与指令

在这里插入图片描述

个人主页:Guiat
归属专栏:Vue

在这里插入图片描述

文章目录

  • 1. Vue 模板语法基础
    • 1.1 文本插值
    • 1.2 原始 HTML
    • 1.3 属性绑定
  • 2. Vue 指令系统
    • 2.1 条件渲染
    • 2.2 列表渲染
    • 2.3 事件处理
    • 2.4 表单输入绑定
  • 3. 计算属性与侦听器
    • 3.1 计算属性
    • 3.2 侦听器
  • 4. 类与样式绑定
    • 4.1 绑定 HTML 类
    • 4.2 绑定内联样式
  • 5. 条件渲染进阶
    • 5.1 v-if 与模板
  • 6. 列表渲染进阶
    • 6.1 数组变更检测
    • 6.2 过滤和排序
  • 7. 事件处理进阶
    • 7.1 事件修饰符详解
    • 7.2 按键修饰符

正文

1. Vue 模板语法基础

Vue 模板语法允许开发者以声明式的方式将数据渲染到 DOM。

1.1 文本插值

<div id="app"><!-- 基本文本插值 --><p>{{ message }}</p><!-- 表达式支持 --><p>{{ message.split('').reverse().join('') }}</p><!-- 数学运算 --><p>{{ count + 1 }}</p><!-- 三元表达式 --><p>{{ isActive ? '激活' : '未激活' }}</p>
</div><script>const app = Vue.createApp({data() {return {message: 'Hello Vue!',count: 10,isActive: true}}}).mount('#app')
</script>

1.2 原始 HTML

<div id="app"><!-- 文本插值会将HTML转义 --><p>{{ rawHtml }}</p><!-- v-html 指令用于输出原始HTML --><p v-html="rawHtml"></p>
</div><script>const app = Vue.createApp({data() {return {rawHtml: '<span style="color: red">这是红色文本</span>'}}}).mount('#app')
</script>

1.3 属性绑定

<div id="app"><!-- 绑定HTML属性 --><div v-bind:id="dynamicId">动态ID元素</div><!-- 简写语法 --><img :src="imageSrc" :alt="imageAlt"><!-- 布尔属性 --><button :disabled="isButtonDisabled">按钮</button><!-- 动态绑定多个属性 --><div v-bind="objectOfAttrs">多属性绑定</div>
</div><script>const app = Vue.createApp({data() {return {dynamicId: 'my-element',imageSrc: 'https://example.com/image.jpg',imageAlt: '示例图片',isButtonDisabled: true,objectOfAttrs: {id: 'container',class: 'wrapper',style: 'color: blue'}}}}).mount('#app')
</script>

2. Vue 指令系统

2.1 条件渲染

<div id="app"><!-- v-if 条件渲染 --><h1 v-if="awesome">Vue 很棒!</h1><h1 v-else>哦不 😢</h1><!-- v-if/v-else-if/v-else 链 --><div v-if="type === 'A'">A类型</div><div v-else-if="type === 'B'">B类型</div><div v-else-if="type === 'C'">C类型</div><div v-else>未知类型</div><!-- v-show 切换元素的显示状态 --><h1 v-show="isVisible">使用v-show控制显示</h1>
</div><script>const app = Vue.createApp({data() {return {awesome: true,type: 'B',isVisible: true}}}).mount('#app')
</script>

2.2 列表渲染

<div id="app"><!-- 基本列表渲染 --><ul><li v-for="item in items" :key="item.id">{{ item.name }}</li></ul><!-- 带索引的列表渲染 --><ul><li v-for="(item, index) in items" :key="item.id">{{ index }} - {{ item.name }}</li></ul><!-- 对象属性遍历 --><ul><li v-for="(value, key, index) in userObject" :key="key">{{ index }}. {{ key }}: {{ value }}</li></ul><!-- 遍历数字范围 --><span v-for="n in 10" :key="n">{{ n }} </span>
</div><script>const app = Vue.createApp({data() {return {items: [{ id: 1, name: '苹果' },{ id: 2, name: '香蕉' },{ id: 3, name: '橙子' }],userObject: {name: '张三',age: 30,city: '上海'}}}}).mount('#app')
</script>

2.3 事件处理

<div id="app"><!-- 基本事件绑定 --><button v-on:click="counter++">点击计数: {{ counter }}</button><!-- 简写语法 --><button @click="greet">问候</button><!-- 内联处理器 --><button @click="say('你好', $event)">说你好</button><!-- 事件修饰符 --><a @click.stop.prevent="handleLink">阻止默认行为并停止传播</a><!-- 按键修饰符 --><input @keyup.enter="submitForm"><!-- 系统修饰键 --><div @click.ctrl="handleCtrlClick">Ctrl + 点击</div>
</div><script>const app = Vue.createApp({data() {return {counter: 0}},methods: {greet() {alert('你好,Vue!')},say(message, event) {alert(message)console.log(event)},handleLink() {console.log('链接被点击,但默认行为被阻止')},submitForm() {console.log('表单提交')},handleCtrlClick() {console.log('Ctrl + 点击被触发')}}}).mount('#app')
</script>

2.4 表单输入绑定

<div id="app"><!-- 文本输入 --><input v-model="message" placeholder="编辑我"><p>消息: {{ message }}</p><!-- 多行文本 --><textarea v-model="description" placeholder="多行输入"></textarea><p>描述: {{ description }}</p><!-- 复选框 --><input type="checkbox" id="checkbox" v-model="checked"><label for="checkbox">{{ checked ? '已选中' : '未选中' }}</label><!-- 多个复选框 --><div><input type="checkbox" id="apple" value="苹果" v-model="checkedFruits"><label for="apple">苹果</label><input type="checkbox" id="banana" value="香蕉" v-model="checkedFruits"><label for="banana">香蕉</label><input type="checkbox" id="orange" value="橙子" v-model="checkedFruits"><label for="orange">橙子</label></div><p>选中的水果: {{ checkedFruits }}</p><!-- 单选按钮 --><div><input type="radio" id="one" value="" v-model="picked"><label for="one"></label><input type="radio" id="two" value="" v-model="picked"><label for="two"></label></div><p>选中的值: {{ picked }}</p><!-- 选择框 --><select v-model="selected"><option disabled value="">请选择</option><option>北京</option><option>上海</option><option>广州</option></select><p>选中的城市: {{ selected }}</p><!-- 修饰符 --><input v-model.lazy="lazyMessage" placeholder="失焦时才更新"><p>Lazy消息: {{ lazyMessage }}</p><input v-model.number="age" type="number" placeholder="自动转为数字"><p>年龄: {{ age }} (类型: {{ typeof age }})</p><input v-model.trim="trimmedMessage" placeholder="自动去除首尾空格"><p>去除空格后: "{{ trimmedMessage }}"</p>
</div><script>const app = Vue.createApp({data() {return {message: '',description: '',checked: false,checkedFruits: [],picked: '',selected: '',lazyMessage: '',age: 0,trimmedMessage: ''}}}).mount('#app')
</script>

3. 计算属性与侦听器

3.1 计算属性

<div id="app"><!-- 原始数据 --><p>原始消息: "{{ message }}"</p><!-- 计算属性 --><p>反转消息: "{{ reversedMessage }}"</p><!-- 方法调用 (每次重新渲染都会调用) --><p>方法反转: "{{ reverseMessage() }}"</p><!-- 带缓存的计算属性 --><p>全名: {{ fullName }}</p><button @click="firstName = ''">修改姓</button><button @click="lastName = ''">修改名</button>
</div><script>const app = Vue.createApp({data() {return {message: 'Hello Vue!',firstName: '张',lastName: '三'}},computed: {// 计算属性会基于其依赖进行缓存reversedMessage() {console.log('计算属性被执行')return this.message.split('').reverse().join('')},// 带getter和setter的计算属性fullName: {get() {return this.firstName + this.lastName},set(newValue) {const names = newValue.split(' ')this.firstName = names[0]this.lastName = names[names.length - 1]}}},methods: {// 方法不会缓存reverseMessage() {console.log('方法被调用')return this.message.split('').reverse().join('')}}}).mount('#app')
</script>

3.2 侦听器

<div id="app"><p>问一个问题: <input v-model="question"></p><p>{{ answer }}</p><p>姓: <input v-model="firstName">名: <input v-model="lastName"></p><p>全名: {{ fullName }}</p><!-- 深度监听示例 --><button @click="updateUserInfo">更新用户信息</button><pre>{{ user }}</pre>
</div><script>const app = Vue.createApp({data() {return {question: '',answer: '请输入问题',firstName: '张',lastName: '三',fullName: '张三',user: {name: '李四',address: {city: '北京'}}}},watch: {// 简单侦听器question(newQuestion, oldQuestion) {if (newQuestion.includes('?')) {this.getAnswer()}},// 侦听多个属性变化firstName(newVal) {this.fullName = newVal + this.lastName},lastName(newVal) {this.fullName = this.firstName + newVal},// 深度侦听对象变化user: {handler(newVal) {console.log('用户信息变化了', newVal)},deep: true // 深度监听},// 立即执行的侦听器'user.name': {handler(newVal) {console.log('用户名变化了', newVal)},immediate: true // 立即执行一次}},methods: {getAnswer() {this.answer = '思考中...'setTimeout(() => {this.answer = '这是一个很好的问题!'}, 1000)},updateUserInfo() {this.user.address.city = '上海'}}}).mount('#app')
</script>

4. 类与样式绑定

4.1 绑定 HTML 类

<div id="app"><!-- 对象语法 --><div :class="{ active: isActive, 'text-danger': hasError }">对象语法绑定类</div><!-- 数组语法 --><div :class="[activeClass, errorClass]">数组语法绑定类</div><!-- 数组中使用对象 --><div :class="[isActive ? activeClass : '', { error: hasError }]">混合语法绑定类</div><!-- 组件上使用 --><my-component :class="{ active: isActive }"></my-component>
</div><script>const app = Vue.createApp({data() {return {isActive: true,hasError: false,activeClass: 'active',errorClass: 'text-danger'}},components: {'my-component': {template: '<p class="base-class">组件</p>'// 最终渲染: <p class="base-class active">组件</p>}}}).mount('#app')
</script>

4.2 绑定内联样式

<div id="app"><!-- 对象语法 --><div :style="{ color: activeColor, fontSize: fontSize + 'px' }">对象语法绑定样式</div><!-- 直接绑定对象 --><div :style="styleObject">绑定样式对象</div><!-- 数组语法 --><div :style="[baseStyles, overridingStyles]">数组语法绑定多个样式对象</div><!-- 自动添加前缀 --><div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }">自动添加浏览器前缀</div>
</div><script>const app = Vue.createApp({data() {return {activeColor: 'red',fontSize: 18,styleObject: {color: 'blue',backgroundColor: '#f0f0f0',padding: '10px'},baseStyles: {fontWeight: 'bold',letterSpacing: '1px'},overridingStyles: {color: 'green',textDecoration: 'underline'}}}}).mount('#app')
</script>

5. 条件渲染进阶

5.1 v-if 与模板

<div id="app"><!-- 使用template元素包裹多个元素 --><template v-if="loginType === 'username'"><label>用户名</label><input placeholder="输入用户名" key="username-input"></template><template v-else><label>邮箱</label><input placeholder="输入邮箱" key="email-input"></template><button @click="toggleLoginType">切换登录类型</button><!-- v-if vs v-show --><h1 v-if="showWithIf">v-if: 条件为真时才渲染</h1><h1 v-show="showWithShow">v-show: 始终渲染但条件为假时隐藏</h1><button @click="toggleShow">切换显示</button>
</div><script>const app = Vue.createApp({data() {return {loginType: 'username',showWithIf: true,showWithShow: true}},methods: {toggleLoginType() {this.loginType = this.loginType === 'username' ? 'email' : 'username'},toggleShow() {this.showWithIf = !this.showWithIfthis.showWithShow = !this.showWithShow}}}).mount('#app')
</script>

6. 列表渲染进阶

6.1 数组变更检测

<div id="app"><ul><li v-for="(item, index) in items" :key="item.id">{{ item.name }} - {{ item.price }}元<button @click="removeItem(index)">删除</button></li></ul><div><input v-model="newItemName" placeholder="商品名称"><input v-model.number="newItemPrice" type="number" placeholder="价格"><button @click="addItem">添加商品</button></div><button @click="sortItems">按价格排序</button><button @click="reverseItems">反转列表</button>
</div><script>const app = Vue.createApp({data() {return {items: [{ id: 1, name: '苹果', price: 5 },{ id: 2, name: '香蕉', price: 3 },{ id: 3, name: '橙子', price: 6 }],newItemName: '',newItemPrice: 0,nextId: 4}},methods: {addItem() {if (this.newItemName && this.newItemPrice > 0) {this.items.push({id: this.nextId++,name: this.newItemName,price: this.newItemPrice})this.newItemName = ''this.newItemPrice = 0}},removeItem(index) {this.items.splice(index, 1)},sortItems() {// 变更方法: 会触发视图更新this.items.sort((a, b) => a.price - b.price)},reverseItems() {// 变更方法: 会触发视图更新this.items.reverse()},updateItem(index) {// 非变更方法: 需要替换数组才能触发更新// this.items[index].price += 1 // 不会触发视图更新// 正确的方式:this.items[index] = { ...this.items[index], price: this.items[index].price + 1 }// 或者使用 Vue.set 或 this.$set (Vue 2)}}}).mount('#app')
</script>

6.2 过滤和排序

<div id="app"><input v-model="searchQuery" placeholder="搜索..."><ul><li v-for="item in filteredItems" :key="item.id">{{ item.name }} - {{ item.price }}元</li></ul><div><button @click="sortOrder = 'asc'">价格升序</button><button @click="sortOrder = 'desc'">价格降序</button><button @click="sortOrder = 'none'">原始顺序</button></div>
</div><script>const app = Vue.createApp({data() {return {items: [{ id: 1, name: '苹果', price: 5 },{ id: 2, name: '香蕉', price: 3 },{ id: 3, name: '橙子', price: 6 },{ id: 4, name: '葡萄', price: 8 }],searchQuery: '',sortOrder: 'none'}},computed: {filteredItems() {// 先过滤let result = this.itemsif (this.searchQuery) {const query = this.searchQuery.toLowerCase()result = result.filter(item => item.name.toLowerCase().includes(query))}// 再排序if (this.sortOrder !== 'none') {result = [...result].sort((a, b) => {return this.sortOrder === 'asc' ? a.price - b.price : b.price - a.price})}return result}}}).mount('#app')
</script>

7. 事件处理进阶

7.1 事件修饰符详解

<div id="app"><!-- 阻止单击事件继续传播 --><a @click.stop="doThis">阻止冒泡</a><!-- 提交事件不再重载页面 --><form @submit.prevent="onSubmit"><input type="text"><button type="submit">提交</button></form><!-- 修饰符可以串联 --><a @click.stop.prevent="doThat">阻止默认行为和冒泡</a><!-- 只有修饰符 --><form @submit.prevent><input type="text"><button type="submit">阻止默认提交</button></form><!-- 添加事件监听器时使用事件捕获模式 --><div @click.capture="doThis">捕获模式<button @click="childClick">子元素</button></div><!-- 只当在 event.target 是当前元素自身时触发处理函数 --><div @click.self="doThat">只有点击这里才触发<button>点击我不会触发父元素事件</button></div><!-- 点击事件将只会触发一次 --><button @click.once="doOnce">只触发一次</button><!-- 滚动事件的默认行为 (滚动) 将立即发生,不等待完成 --><div @scroll.passive="onScroll">被动监听的滚动区域</div>
</div><script>const app = Vue.createApp({methods: {doThis() {console.log('doThis 被调用')},doThat() {console.log('doThat 被调用')},onSubmit() {console.log('表单提交')},childClick() {console.log('子元素被点击')},doOnce() {console.log('这个处理函数只会触发一次')},onScroll() {console.log('滚动中...')}}}).mount('#app')
</script>

7.2 按键修饰符

<div id="app"><!-- 按下Enter键时调用 --><input @keyup.enter="submit"><!-- 按下Tab键时调用 --><input @keyup.tab="handleTab"><!-- 按下Delete键时调用 --><input @keyup.delete="handleDelete"><!-- 按下Esc键时调用 --><input @keyup.esc="handleEscape"><!-- 按下空格键时调用 --><input @keyup.space="handleSpace"><!-- 按下上方向键时调用 --><input @keyup.up="handleUp"><!-- 按下Page Down键时调用 --><input @keyup.page-down="handlePageDown"><!-- 组合按键 --><input @keyup.alt.enter="handleAltEnter"><!-- Ctrl + 点击 --><div @click.ctrl="handleCtrlClick">Ctrl + Click</div><!-- 精确的系统修饰符 --><button @click.ctrl.exact="onCtrlClick">仅当按下Ctrl时</button><button @click.exact="onClickWithoutModifiers">没有任何系统修饰符</button>
</div><script>const app = Vue.createApp({methods: {submit() {console.log('提交表单')},handleTab() {console.log('Tab键被按下')},handleDelete() {console.log('Delete键被按下')},handleEscape() {console.log('Esc键被按下')},handleSpace() {console.log('空格键被按下')},handleUp() {console.log('上方向键被按下')},handlePageDown() {console.log('Page Down键被按下')},handleAltEnter() {console.log('Alt + Enter被按下')},handleCtrlClick() {console.log('Ctrl + Click被触发')},onCtrlClick() {console.log('仅当按下Ctrl时触发')},onClickWithoutModifiers() {console.log('没有任何系统修饰符时触发')}}}).mount('#app')
</script>

结语
感谢您的阅读!期待您的一键三连!欢迎指正!

在这里插入图片描述

相关文章:

  • 图灵奖得主LeCun:DeepSeek开源在产品层是一种竞争,但在基础方法层更像是一种合作;新一代AI将情感化
  • 【Linux】线程ID、线程管理、与线程互斥
  • 【概率论】条件期望
  • rebase和merge的区别
  • 【图片识别改名工具】图片文件区域OCR识别并自动重命名,批量识别指定区域根据指定识别文字批量改名,基于WPF和阿里云的技术方式实现
  • Ethan独立开发产品日报 | 2025-04-18
  • 汽车故障诊断工作原理:从需求到AUTOSAR诊断模块协作的浅析
  • Android 热点二维码简单示例
  • 0801ajax_mock-网络ajax请求1-react-仿低代码平台项目
  • 论文阅读:2024 ICLR Workshop. A STRONGREJECT for Empty Jailbreaks
  • 每日两道leetcode
  • SRS流媒体服务器
  • 学习笔记十八——Rust 封装
  • 【UniApp】Vue2 scss 预编译器默认已由 node-sass 更换为 dart-sass
  • NFC碰一碰发视频系统OEM定制,源码搭建注意事项
  • 【FreeRTOS进阶】优先级翻转现象详解及解决方案
  • React-useRef
  • 【Redis】从单机架构到分布式,回溯架构的成长设计美学
  • 数据驱动增长:大数据与营销自动化的结合之道
  • 学习设计模式《三》——适配器模式
  • 经济日报:“关税讹诈”拦不住中国制造升级
  • 男子拍摄女性视频后在网上配发诱导他人违法犯罪文字,已被警方行拘
  • 一季度工业对宏观经济增长的贡献率达36.3%
  • 经济日报:扩大内需与扩大开放并行不悖
  • 夜读丨石头比月光温柔
  • 2月美国三大债主均增持美国国债,中国增持235亿美元