Vue-模板和选项式API
模板
确定模板有几种方式
- 以容器的
innerHTML
做为模板 - 以
template
选项做为模板 - 以
render
函数做为模板
优先级: render函数 > template > 容器
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <script src="../node_modules/vue/dist/vue.global.js"></script> </head> <body> <!-- 容器指定的innerHTML模板 < template指定模板 --> <div id="app">由容器指定的模板</div> <script> const { createApp, h } = Vue const app = createApp({ template: `<h1>由template指定的模板</h1>`, render: () => h('div', '由render函数指定的模板'), }) app.mount('#app') </script> </body> </html>
模板语法
- 插值语法: 在
{{}}
中书写的语法
主要应用于文本节点
<div id="app"> {{msg}} </div>
- 指令语法: 以
v-
开头的语法
主要应用于属性节点
<a v-bind:href="url">百度</a>
插值语法细节
- 直接访问实例上的属性
<div id="app"> <!-- 直接使用instance实例上的属性 --> 姓名: {{name}} <br /> 女友: {{gf.name}} <br /> 喜欢的书: {{books[0].name}} <br /> </div> <script> const { createApp } = Vue const vm = createApp({ data() { return { name: 'xiaoming', age: 20, gf: { name: 'xiaomei', age: 18, }, books: [{ name: 'Vue' }, { name: 'React' }], } }, }).mount('#app') </script>
- 使用表达式
赋值表达式, 运算表达式, 条件表达式, 函数表达式
{{ number + 1 }} {{ ok ? 'YES' : 'NO' }} {{ message.split('').reverse().join('') }} <!-- 这是一个语句,而非表达式 --> <!-- {{ var a = 1 }} --> <!-- 条件控制也不支持,请使用三元表达式 --> <!-- {{ if (ok) { return message } }} -->
属性绑定指令
将 元素 的一个属性值和data中的一个变量绑定
同样可以使用js表达式
<div id="app"> <!-- 完整的写法 --> <a v-bind:href="url">百度</a> <!-- 简写(推荐) --> <a :href="url">百度</a> </div> const { createApp } = Vue const vm = createApp({ data() { return { url: 'http://www.baidu.com', } }, }).mount('#app')
事件绑定指令
将JS事件和对应的处理函数绑定
v-on:事件名="函数名" // 简写 @事件名="函数名" <button @click="handleClick">点击</button> methods: { handleClick() { alert('hello') } }
事件修饰符:
.prevent
: 阻止默认行为.stop
: 阻止冒泡.once
: 事件只会触发一次
<body> <div id="app"> <a @click.prevent="" href="http://www.baidu.com">baidu</a> </div> <script> const { createApp } = Vue const vm = createApp({}).mount('#app') // 原生js方式 // document.querySelector('a').addEventListener('click', function (e) { // // 调用事件对象的preventDefault方法, 阻止默认行为 // // 对于a元素而言, 默认行为就是跳转页面 // e.preventDefault() // }) </script> </body>
<body> <div id="app"> <ul @click="handleUl"> <!-- 1. `.stop` 阻止事件向上冒泡 2. 事件修饰符可以连用 --> <li @click.stop="handleLi">1</li> <li>2</li> <li>3</li> </ul> </div> <script> const { createApp } = Vue const vm = createApp({ methods: { handleUl() { console.log('ul被点击了...') }, handleLi() { console.log('li被点击了...') }, }, }).mount('#app') </script> </body>
按键修饰符:
- .enter: 回车键
- .up: 上
- .down: 下
- .left: 左
- .right: 右
系统功能键
- .ctrl
- .alt
- .shift
<body> <div id="app"> <input type="text" @keyup.enter="submit" /> </div> <script> const { createApp } = Vue const vm = createApp({ methods: { submit() { console.log('输入了数据, 按下回车键') }, }, }).mount('#app') </script> </body>
双向绑定指令
双向绑定指令 通常应用于 表单元素
- 数据 的改变影响 视图
- 视图 的改变影响 数据
<div id="app"> <input type="text" v-model="username" /> <p>{{username}}</p> </div> <script> const { createApp } = Vue const vm = createApp({ data() { return { username: '', } }, }).mount('#app') </script>
v-model 将表单元素的 值 和 data中定义的状态绑定
text
和textarea
使用value
属性和input
事件checkbox
和radio
使用checked
属性和change
事件select
字段将value
作为prop并将change
作为事件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Vue.js Form Example</title> <script src="../node_modules/vue/dist/vue.global.js"></script> </head> <body> <div id="app"> <form @submit.prevent="submitForm"> <label for="username">用户名: </label> <input type="text" id="username" v-model="form.username"><br> <label for="password">密码: </label> <input type="password" id="password" v-model="form.password"><br> <label for="age">年龄: </label> <input type="text" id="age" v-model="form.age"><br> <label for="bio">个人签名: </label> <textarea v-model="form.bio"></textarea><br><br> <label>性别: </label> <input type="radio" id="male" value="male" v-model="form.sex"> <label for="male">男</label> <input type="radio" id="female" value="female" v-model="form.sex"> <label for="female">女</label><br> <label>爱好: </label> <input type="checkbox" id="eat" value="eat" v-model="form.hobbies"> <label for="eat">吃</label> <input type="checkbox" id="sleep" value="sleep" v-model="form.hobbies"> <label for="sleep">睡</label><br> <label for="city">城市: </label> <select v-model="form.city"> <option value="nanjing">南京</option> <option value="wuxi">无锡</option> <option value="taizhou">泰州</option> </select><br> <input type="submit" value="提交"> </form> </div> <script> const { createApp } = Vue; createApp({ data() { return { form: { username: '', password: '', age: '', sex: '', hobbies: [], city: '', bio: '' } }; }, methods: { submitForm() { // 在这里处理表单提交,例如发送到服务器 console.log(this.form); } } }).mount('#app'); </script> </body> </html>
计算属性
计算属性用于对原始数据的再次加工
- 有缓存
- 调试方便
<body> <!-- 需求: 实现字符串的反转 eg. abc 转换成 cba --> <div id="app"> 请输入一个字符串: <input type="text" v-model="msg" /> <br /> <h3>反转后的字符串: {{reverseMsg}}</h3> </div> <script> const { createApp } = Vue const app = createApp({ data: function() { return {msg: '',} }, computed: { // 编写一个函数, 这个函数会被做为该计算属性的getter reverseMsg() { console.log('计算属性被执行了...') // 该函数的返回值, 做为访问计算属性的结果 return this.msg.split('').reverse().join('') }, }, }) const vm = app.mount('#app') </script> </body>
侦听器
通过watch配置项, 监听已经存在的属性的改变
watch: { // 监听data中的firstName属性 firstName() { // 执行一系列的操作 }, },
<body> <div id="app"> 姓: <input type="text" v-model="lastName" /> <br /> 名: <input type="text" v-model="firstName" /> <br /> 全名(侦听器实现): {{fullName}} </div> <script> const { createApp } = Vue const vm = createApp({ data() { return { lastName: '', firstName: '', fullName: '', } }, watch: { // 侦听lastName的变化, 当lastName变化时, 执行该函数 lastName() { this.fullName = this.lastName + this.firstName }, // 侦听firstName的变化, 当firstName变化时, 执行该函数 firstName() { this.fullName = this.lastName + this.firstName }, }, }).mount('#app') </script> </body>
在watch对应的回调函数中, 可以获取到新值
和 旧值
watch: { // 在watch对应的回调函数中, 可以得到新值和旧值 // 对于简单数据类型, 可以获取新旧值 // 对于引用数据类型, 不能获取旧值 firstName(newValue, oldValue) { // 一对多: 监听某一个属性的改变, 做一系列的操作 console.log('firstName改变了...') console.log('新的值:', newValue) console.log('旧的值:', oldValue) }, },
访问响应式引用(对象, 数组, 函数)的旧值和新值:
const { createApp, ref } = Vue const app = createApp({ setup() { const someData = ref('initial value') // 使用 watch 函数 watch(someData, (newVal, oldVal) => { console.log('新值:', newVal); console.log('旧值:', oldVal); }) // ...其他逻辑 return { someData } } }).mount('#app')
计算属性 VS 侦听器
-
是否会在vm实例中挂载新属性?
- computed会
- watch不会
-
对应关系
- computed是
多对一
, 可以同时监听多个值改变, 最终计算得到一个新的属性 - watch是
一对多
, 主要监听一个属性的变化, 执行多种逻辑
- computed是
-
能否获取新旧值?
- computed不能
- watch能
侦听器的高级用法
- immediate: true => 立即执行watch的回调
- flush: 'post' => 让watch的回调在DOM更新之后执行
- 对watch值类型属性, 可以在watch的回调中获取到新旧值
条件渲染
当条件满足时, 渲染到页面, 主要指令: v-if
和v-show
当flag为false时:
- v-if: 不会创建元素
- v-show: 创建元素, 但是display=none
<body> <div id="app"> <!-- 当一个内容有复杂逻辑时, 使用v-if --> <div v-if="flag">我是通过v-if控制的</div> <div v-else>我是通过v-else控制的</div> <!-- 当一个内容需要切换显示时, 使用v-show --> <div v-show="flag">我是通过v-show控制的</div> <div v-show="!flag">我是通过v-show控制的</div> </div> <script> const { createApp } = Vue const vm = createApp({ data() { return { flag: true, } }, }).mount('#app') </script> </body>
使用表达式:
<div v-if="flag == true">这是用v-if渲染的元素</div>
<body> <div id="app"> <button @click="flag = !flag">切换显示/隐藏</button> <div v-show="flag">div显示的内容</div> </div> <script> const { createApp } = Vue const vm = createApp({ data() { return { flag: true, } }, methods: { toggle() { this.flag = !this.flag }, }, }).mount('#app') </script> </body>
列表渲染
通过v-for
遍历数组或者对象
- 获取元素
v-for="item in items"
v-for="(item, index) in items"
<body> <div id="app"> <ul> <!-- 在指令表达式中, in前面的参数表示数组元素 --> <!-- <li v-for="item in items">{{item}}</li> --> <!-- (元素, 下标) in 数组 --> <li v-for="(value, key) in items">{{key}} -- {{value}}</li> </ul> </div> <script> const { createApp } = Vue const vm = createApp({ data() { return { items: ['test1', 'test2', 'test3'], } }, }).mount('#app') </script> </body>
-
遍历对象
-
只取值:
v-for="value in obj"
-
取键和值:
v-for="(value, key) in obj"
-
取键和值和索引:
v-for="(value, key, index) in obj"
-
样式绑定
通过绑定class
属性 或者 style
属性 修改样式
-
绑定class属性
-
数组写法
-
对象写法
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <script src="../node_modules/vue/dist/vue.global.js"></script> <style> .red { color: red; } .blue { color: skyblue; } </style> </head> <body> <div id="app"> <!-- 原生的写法 --> <span class="red blue">一段文字</span> <!-- 绑定class属性 -- 对象的写法 --> <span :class="obj">对象的写法</span> <!-- 绑定class属性 -- 数组的写法(推荐) --> <span :class="arr">数组的写法</span> <span :class="foo">绑定一个变量</span> <span :class="flag ? 'red' : 'blue'">使用表达式</span> </div> <script> const { createApp } = Vue const vm = createApp({ data() { return { obj: { red: true, blue: true, }, arr: ['red', 'blue'], foo: 'red', flag: true, } }, }).mount('#app') </script> </body> </html>
- 绑定style属性
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <script src="../node_modules/vue/dist/vue.global.js"></script> </head> <body> <div id="app"> <!-- 原生的写法 --> <div style="font-size: 32px; color: red">原生的写法</div> <!-- 绑定style属性 -- 对象写法 --> <div :style="obj">对象的写法</div> </div> <script> const { createApp } = Vue const vm = createApp({ data() { return { obj: { // 'font-size': '32px', fontSize: '32px', color: 'red', }, } }, }).mount('#app') </script> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <!-- 1.1 引入vue.js --> <script src="../node_modules/vue/dist/vue.global.js"></script> <!-- 2.2 实例静态页面(CSS部分) --> <style> * { margin: 0; padding: 0; } li { list-style: none; } .menu-tab { display: flex; justify-content: space-between; margin: 50px auto; height: 40px; width: 700px; border: 1px solid #eee; border-bottom: 1px solid #e4393c; background-color: #f7f7f7; box-sizing: border-box; } .menu-tab .menu-item { flex: 1; display: flex; justify-content: center; align-items: center; font-size: 14px; color: #666; cursor: pointer; } .menu-tab .menu-item:hover { color: #e4393c; } .menu-tab .menu-item.current { color: #fff; background-color: #e4393c; } </style> </head> <body> <!-- 1.2 编写页面容器 --> <div id="app"> <!-- 2.1 实例静态页面(HTML部分) --> <ul class="menu-tab"> <li v-for="(item, index) in items" class="menu-item" :class="index == active ? 'current' : '' " @click="handleClick(index)" > {{item}} </li> </ul> </div> <!-- 1.3 创建vue实例对象 --> <script> const { createApp } = Vue const vm = createApp({ data() { return { items: ['商品介绍', '规格与包装', '售后保障', '商品评价(2000+)', '手机社区'], active: 0, } }, methods: { handleClick(i) { console.log(i) this.active = i }, }, }).mount('#app') </script> </body> </html>
本文作者:Khru
本文链接:https://www.cnblogs.com/khrushchefox/p/18573272
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理