资讯详情

资讯详情

Vue 3 基础:模板语法、响应式、指令

前言上一篇讲了 JavaScript、DOM 和 ES6这一篇进入Vue 3。Vue 是目前最主流的前端框架之一它把数据驱动视图这个理念做到了极致你只管改数据页面自动更新。这篇覆盖 Vue 3 的基础三件套模板语法、响应式、指令学完就能写简单页面了。期待和你的一起进步一、Vue 工程搭建 Vue 项目结构认识1.1 创建 Vue 3 项目用官方推荐的 Vite 创建bashnpm create vuelatest按提示输入项目名选择需要的功能Router、Pinia 等然后bashcd 项目名 npm install npm run dev1.2 项目结构textmy-vue-app/ ├── public/ # 静态资源不参与打包 ├── src/ # 源码目录 │ ├── assets/ # 静态资源参与打包 │ ├── components/ # 公共组件 │ ├── views/ # 页面组件 │ ├── router/ # 路由配置 │ ├── stores/ # Pinia 状态管理 │ ├── App.vue # 根组件 │ └── main.js # 入口文件 ├── index.html # HTML 模板 ├── package.json # 项目依赖和脚本 └── vite.config.js # Vite 配置1.3 入口文件 main.jsjavascriptimport { createApp } from vue import App from ./App.vue import router from ./router const app createApp(App) app.use(router) app.mount(#app)1.4 我的理解Vue 项目结构就像一栋房子index.html是地基main.js是大门程序从这里进来App.vue是主框架所有页面都装在它里面components/是家具可复用的组件放这里views/是房间每个页面一个核心一句话Vite 创建项目main.js 是入口App.vue 是根组件components 放公共组件views 放页面。二、单文件组件 SFC2.1 什么是 SFCSFCSingle-File Component就是单文件组件一个.vue文件就是一个组件包含三部分vuetemplate !-- HTML 结构 -- /template script setup // JS 逻辑 /script style scoped /* CSS 样式 */ /style2.2 三部分说明部分作用说明template模板定义组件的 HTML 结构script setup逻辑定义数据、方法等setup是 Vue 3 语法糖style scoped样式scoped表示样式只作用于当前组件2.3 完整示例vuetemplate div classbox h1{{ title }}/h1 button clickchangeTitle改标题/button /div /template script setup import { ref } from vue const title ref(Hello Vue 3) function changeTitle() { title.value 标题被改了 } /script style scoped .box { padding: 20px; } h1 { color: #42b983; } /style2.4 我的理解SFC 就像把 HTML、JS、CSS 打包成一个文件。以前写页面结构、样式、逻辑分三个文件现在一个.vue文件全搞定相关代码放一起好维护。核心一句话SFC 一个文件包含 template、script、style 三部分scoped 让样式只作用于当前组件。三、模板语法——文本插值3.1 什么是文本插值用双大括号{{ }}把数据渲染到页面上。vuetemplate p{{ message }}/p p{{ count 1 }}/p p{{ name.toUpperCase() }}/p /template script setup import { ref } from vue const message ref(Hello) const count ref(10) const name ref(vue) /script渲染结果textHello 11 VUE3.2 插值里可以写什么变量{{ message }}表达式{{ count 1 }}方法调用{{ name.toUpperCase() }}三元运算{{ flag ? 是 : 否 }}不能写语句{{ if (x) {} }}❌变量声明{{ let a 1 }}❌3.3 我的理解文本插值就像在 HTML 里挖个坑用数据填进去。{{ }}就是那个坑Vue 会把里面的表达式的值算出来填到页面上。核心一句话{{ }} 插值可以写表达式不能写语句。四、v-bind 动态属性4.1 什么是 v-bindv-bind 用来动态绑定 HTML 属性简写是:。vuetemplate !-- 完整写法 -- img v-bind:srcimgUrl / !-- 简写 -- img :srcimgUrl / a :hreflink链接/a div :classclassName/div /template script setup import { ref } from vue const imgUrl ref(https://example.com/logo.png) const link ref(https://www.baidu.com) const className ref(active) /script4.2 绑定布尔属性vuetemplate button :disabledisDisabled按钮/button input :typeinputType / /template script setup import { ref } from vue const isDisabled ref(true) const inputType ref(password) /script4.3 我的理解v-bind就是让属性值从写死变成跟着数据走。以前srclogo.png是固定的现在:srcimgUrl跟着imgUrl变化。核心一句话v-bind 动态绑定属性简写是冒号 :。五、v-text 与 v-html5.1 v-textv-text 用于渲染文本内容相当于innerText。vuetemplate p v-textmessage/p /template script setup import { ref } from vue const message ref(Hello Vue) /script渲染结果htmlpHello Vue/p5.2 v-htmlv-html 用于渲染 HTML 内容相当于innerHTML。vuetemplate div v-htmlhtmlContent/div /template script setup import { ref } from vue const htmlContent ref(b加粗/bi斜体/i) /script渲染结果htmldivb加粗/bi斜体/i/div5.3 v-text vs v-html vs 插值方式说明是否解析 HTML{{ }}插值❌ 不解析v-text文本❌ 不解析v-htmlHTML✅ 解析5.4 v-html 的安全风险v-html 会解析 HTML可能被 XSS 攻击。不要用它渲染用户输入的内容。vue!-- ❌ 危险用户可能输入 scriptalert(xss)/script -- div v-htmluserInput/div5.5 我的理解v-text是安全模式原样显示v-html是渲染模式会解析标签但有风险核心一句话v-text 不解析 HTMLv-html 解析 HTML 但有 XSS 风险。六、条件渲染v-if / v-else-if / v-else6.1 基本用法vuetemplate p v-ifscore 90优秀/p p v-else-ifscore 60及格/p p v-else不及格/p /template script setup import { ref } from vue const score ref(85) /script6.2 v-if 的本质v-if是真正的条件渲染条件为 false 时元素从 DOM 中移除条件为 true 时重新创建。6.3 配合 template如果多个元素要一起控制用template包裹vuetemplate template v-ifisLogin p欢迎回来/p button退出/button /template template v-else p请先登录/p button登录/button /template /template6.4 我的理解v-if就像把元素从页面上删掉条件不满足元素直接消失DOM 里也没有。核心一句话v-if 是真正的条件渲染false 时元素从 DOM 移除。七、v-if 与 v-show 的区别7.1 对比表对比项v-ifv-show实现方式创建/销毁元素切换 display 样式初始渲染条件为 false 时不渲染始终渲染只是隐藏切换开销高低初始开销低false 时不渲染高始终渲染适用场景切换少切换频繁7.2 代码示例vuetemplate !-- v-if条件为 false 时DOM 里没有这个元素 -- p v-ifflagv-if 内容/p !-- v-showDOM 里始终有只是 display: none -- p v-showflagv-show 内容/p /template7.3 如何选择切换频繁用v-show只改 CSS开销小切换少用v-if不渲染省资源条件很少变用v-if需要配合 v-else只能用v-if7.4 我的理解v-if像搬家不用了就搬走用的时候再搬回来搬来搬去很累v-show像拉窗帘东西一直在只是挡起来拉一下很快核心一句话频繁切换用 v-show条件少变用 v-if。八、列表渲染v-for8.1 基本用法vuetemplate ul li v-foritem in items :keyitem.id {{ item.name }} /li /ul /template script setup import { ref } from vue const items ref([ { id: 1, name: 苹果 }, { id: 2, name: 香蕉 }, { id: 3, name: 橙子 } ]) /script8.2 带索引vuetemplate ul li v-for(item, index) in items :keyitem.id {{ index }} - {{ item.name }} /li /ul /template8.3 遍历对象vuetemplate ul li v-for(value, key, index) in obj :keykey {{ index }} - {{ key }}: {{ value }} /li /ul /template script setup import { ref } from vue const obj ref({ name: 张三, age: 18, city: 北京 }) /script8.4 key 的重要性key 是 Vue 识别节点身份的唯一标识必须唯一且稳定。vue!-- ✅ 推荐用唯一 id -- li v-foritem in items :keyitem.id !-- ❌ 不推荐用 index删除元素时会出错 -- li v-foritem in items :keyindex为什么不用 index如果列表是[A, B, C]用 index 作 key 是[0, 1, 2]。删除 B 后变成[A, C]index 变成[0, 1]。Vue 会以为 0 还是 A1 从 B 变成了 C导致复用错误。8.5 我的理解v-for就像复印机你给一个模板它按数组长度复印多份。key就像每份复印件的编号Vue 靠它识别哪份是哪份。核心一句话v-for 遍历数组/对象必须加 keykey 要唯一稳定别用 index。九、事件处理v-on简写 9.1 基本用法vuetemplate button v-on:clickhandleClick点我/button !-- 简写 -- button clickhandleClick点我/button /template script setup function handleClick() { console.log(点击了) } /script9.2 内联写法vuetemplate button clickcount加 1/button button clicksayHello(张三)打招呼/button /template script setup import { ref } from vue const count ref(0) function sayHello(name) { console.log(你好 name) } /script9.3 事件修饰符修饰符说明.stop阻止冒泡.prevent阻止默认行为.once只触发一次.self只有自己触发才执行.capture捕获阶段触发vuetemplate a click.preventhandleClick hrefhttps://www.baidu.com链接/a button click.oncehandleClick只触发一次/button div click.selfhandleClick只有点自己才触发/div /template9.4 按键修饰符vuetemplate input keyup.entersubmit / input keyup.esccancel / /template9.5 我的理解v-on就是给元素绑事件。修饰符是给事件加条件.prevent是阻止默认行为.stop是阻止冒泡.once是只执行一次。核心一句话v-on 绑事件简写 修饰符给事件加条件。十、表单绑定v-model10.1 什么是 v-modelv-model 实现表单元素和数据的双向绑定数据变 → 表单变表单变 → 数据变vuetemplate input v-modelmessage / p你输入的是{{ message }}/p /template script setup import { ref } from vue const message ref() /script10.2 各种表单元素vuetemplate !-- 文本框 -- input v-modeltext / !-- 多行文本 -- textarea v-modeldesc/textarea !-- 复选框单个布尔 -- input typecheckbox v-modelagree / !-- 复选框多个数组 -- input typecheckbox value读书 v-modelhobbies / input typecheckbox value跑步 v-modelhobbies / !-- 单选框 -- input typeradio value男 v-modelgender / input typeradio value女 v-modelgender / !-- 下拉框 -- select v-modelcity option value北京北京/option option value上海上海/option /select /template script setup import { ref } from vue const text ref() const desc ref() const agree ref(false) const hobbies ref([]) const gender ref(男) const city ref(北京) /script10.3 修饰符修饰符说明.lazy失去焦点才更新.number转成数字.trim去掉首尾空格vuetemplate input v-model.lazytext / input v-model.numberage typenumber / input v-model.trimname / /template10.4 我的理解v-model就是表单和数据之间的双向通道。你改数据表单跟着变你填表单数据跟着变。核心一句话v-model 双向绑定表单和数据互相同步支持 .lazy/.number/.trim 修饰符。十一、响应式基础——ref11.1 什么是 refref 用于定义基本类型的响应式数据返回一个带.value属性的对象。vuetemplate p{{ count }}/p button clickcount加 1/button /template script setup import { ref } from vue const count ref(0) console.log(count.value) // 0JS 中要加 .value /script11.2 关键点位置是否加 .valuetemplate中❌ 不加script中✅ 加vuetemplate !-- 模板里不用加 .value -- p{{ count }}/p /template script setup import { ref } from vue const count ref(0) // JS 里要加 .value console.log(count.value) count.value /script11.3 ref 也能定义对象/数组javascriptconst obj ref({ name: 张三, age: 18 }) const arr ref([1, 2, 3]) // 访问 console.log(obj.value.name) console.log(arr.value[0]) // 修改 obj.value.name 李四 arr.value.push(4)11.4 我的理解ref就像给数据套了个壳。你要访问壳里的值得用.value打开壳。但在模板里Vue 自动帮你打开壳所以不用写.value。核心一句话ref 定义响应式数据JS 中加 .value模板中不加。十二、响应式基础——reactive12.1 什么是 reactivereactive 用于定义对象类型的响应式数据返回一个 Proxy 对象。vuetemplate p{{ state.name }}/p p{{ state.age }}/p /template script setup import { reactive } from vue const state reactive({ name: 张三, age: 18 }) // 直接访问不用 .value console.log(state.name) state.age /script12.2 ref vs reactive对比项refreactive适用类型基本类型 对象只能对象/数组JS 访问.value直接访问模板访问不加不加重新赋值count.value 1不能整个替换推荐度⭐⭐⭐⭐⭐⭐⭐⭐12.3 reactive 的坑javascriptlet state reactive({ count: 0 }) // ❌ 不能整个替换会丢失响应式 state reactive({ count: 1 }) // ✅ 只能改属性 state.count 112.4 我的理解ref像万能盒子基本类型和对象都能装但访问要.valuereactive像专用盒子只能装对象但访问方便实际开发中推荐统一用 ref简单省事。核心一句话reactive 只能定义对象不能整个替换推荐统一用 ref。十三、v-model 表单绑定13.1 回顾v-model是:valueinput的语法糖vue!-- v-model 写法 -- input v-modeltext / !-- 等价于 -- input :valuetext inputtext $event.target.value /13.2 在组件上使用v-model也可以用在组件上实现父子组件双向绑定后面组件篇会讲。vue!-- 父组件 -- Child v-modelmsg / !-- 等价于 -- Child :modelValuemsg update:modelValuemsg $event /13.3 多个 v-modelvue!-- Vue 3 支持多个 v-model -- UserForm v-model:namename v-model:ageage /13.4 我的理解v-model在表单上是双向绑定在组件上是父子双向通信的语法糖。核心就是:valueinput。核心一句话v-model 是 :value input 的语法糖表单和组件都能用。十四、class 绑定14.1 对象语法vuetemplate div :class{ active: isActive, text-red: isRed }/div /template script setup import { ref } from vue const isActive ref(true) const isRed ref(false) /script渲染结果htmldiv classactive/div14.2 数组语法vuetemplate div :class[activeClass, redClass]/div div :class[isActive ? active : , text-red]/div /template script setup import { ref } from vue const activeClass ref(active) const redClass ref(text-red) const isActive ref(true) /script14.3 与普通 class 共存vuetemplate div classstatic :class{ active: isActive }/div /template渲染结果htmldiv classstatic active/div14.4 我的理解class绑定就是动态控制类名条件满足就加某个类不满足就不加。比手动classList.add方便多了。核心一句话class 绑定支持对象和数组语法可以和普通 class 共存。十五、style 绑定15.1 对象语法vuetemplate div :style{ color: textColor, fontSize: fontSize px }/div /template script setup import { ref } from vue const textColor ref(red) const fontSize ref(20) /script渲染结果htmldiv stylecolor: red; font-size: 20px;/div15.2 数组语法vuetemplate div :style[baseStyle, extraStyle]/div /template script setup import { ref } from vue const baseStyle ref({ color: red }) const extraStyle ref({ fontSize: 20px }) /script15.3 自动加前缀Vue 会自动给需要前缀的 CSS 属性加浏览器前缀vuediv :style{ transform: rotate(45deg) }/div会自动生成-webkit-transform等前缀。15.4 我的理解style绑定就是动态控制内联样式。和class绑定类似但class控制类名style控制具体样式属性。核心一句话style 绑定支持对象和数组语法Vue 自动加浏览器前缀。十六、computed 计算属性16.1 什么是 computedcomputed 用于根据已有数据计算出新数据有缓存机制。vuetemplate p原价{{ price }}/p p数量{{ count }}/p p总价{{ total }}/p /template script setup import { ref, computed } from vue const price ref(10) const count ref(3) const total computed(() price.value * count.value) /script16.2 计算属性的特点特点说明有缓存依赖不变时不重新计算必须有返回值用return返回结果只读默认只读要改需写 setter16.3 可写计算属性javascriptconst fullName computed({ get() { return firstName.value lastName.value }, set(value) { const parts value.split( ) firstName.value parts[0] lastName.value parts[1] } }) fullName.value 李四 王五 // 会触发 set16.4 computed vs methods对比项computedmethods缓存✅ 有❌ 无调用当属性用当方法用适用依赖数据算新数据事件处理vuetemplate p{{ computedValue }}/p !-- 不加括号 -- p{{ methodValue() }}/p !-- 加括号 -- /template16.5 我的理解computed就像带缓存的公式。你写total price * countVue 会记住结果。只要price和count不变total就直接用缓存不重新算。methods每次调用都重新执行。核心一句话computed 有缓存依赖不变不重算必须有返回值。十七、watch 监听器17.1 什么是 watchwatch 用于监听数据变化数据变了就执行某些操作。vuetemplate input v-modelkeyword / /template script setup import { ref, watch } from vue const keyword ref() watch(keyword, (newVal, oldVal) { console.log(新值, newVal) console.log(旧值, oldVal) }) /script17.2 监听对象javascriptconst state reactive({ name: 张三, age: 18 }) // 监听整个对象深度监听 watch(state, (newVal, oldVal) { console.log(state 变了) }, { deep: true }) // 监听某个属性 watch(() state.name, (newVal) { console.log(name 变了, newVal) })17.3 配置项配置项说明immediate: true立即执行一次deep: true深度监听对象内部变化javascriptwatch(keyword, (newVal) { console.log(newVal) }, { immediate: true, deep: true })17.4 watch vs computed对比项watchcomputed作用监听变化做副作用计算新值返回值无有缓存无有适用异步请求、日志派生数据17.5 我的理解computed是算出新数据根据 A 算出 Bwatch是盯着数据做事情A 变了就去请求接口、打日志核心一句话watch 监听变化做副作用computed 计算新数据有缓存。十八、数组与对象的响应式操作18.1 数组的响应式方法Vue 3 用 Proxy 实现响应式数组的原生方法都能触发更新javascriptconst arr ref([1, 2, 3]) arr.value.push(4) // ✅ 触发更新 arr.value.pop() // ✅ arr.value.splice(0, 1) // ✅ arr.value[0] 10 // ✅Vue 3 支持 arr.value.length 0 // ✅18.2 对象的响应式操作javascriptconst state reactive({ name: 张三 }) state.name 李四 // ✅ 触发更新 state.age 18 // ✅ 新增属性也响应式 delete state.name // ✅ 删除属性也响应式18.3 Vue 2 vs Vue 3操作Vue 2Vue 3数组索引赋值❌ 不响应✅ 响应数组 length 修改❌ 不响应✅ 响应对象新增属性❌ 不响应✅ 响应对象删除属性❌ 不响应✅ 响应Vue 3 用 Proxy 解决了 Vue 2 的这些坑。18.4 我的理解Vue 3 的响应式基于Proxy可以拦截对象的任意操作所以数组索引赋值、对象新增属性这些 Vue 2 搞不定的Vue 3 都能响应。核心一句话Vue 3 用 Proxy数组和对象的任意操作都能触发响应式。十九、核心口诀知识点口诀工程搭建Vite 创建main.js 入口App.vue 根组件SFC一个文件含 template、script、stylescoped 隔离样式文本插值{{ }} 插值可写表达式不能写语句v-bind动态绑定属性简写 :v-text/v-htmlv-text 不解析v-html 解析但有 XSS 风险v-if真正的条件渲染false 时从 DOM 移除v-if vs v-show频繁切换用 v-show条件少变用 v-ifv-for遍历数组/对象必须加 key别用 indexv-on绑事件简写 修饰符加条件v-model双向绑定表单和数据同步ref响应式数据JS 加 .value模板不加reactive只能对象不能整个替换推荐统一用 refclass 绑定对象/数组语法动态控制类名style 绑定对象/数组语法动态控制内联样式computed有缓存依赖不变不重算必须有返回值watch监听变化做副作用支持 immediate/deep数组对象响应式Vue 3 用 Proxy任意操作都响应二十、常见易错点易错点说明ref 在模板里加 .value模板里不用加Vue 自动解包ref 在 JS 里忘加 .valueJS 里必须加否则拿到的是 ref 对象v-for 忘加 key必须加且要唯一稳定别用 indexv-if 和 v-for 同用不推荐v-if 优先级问题用 template 包v-html 渲染用户输入有 XSS 风险不要渲染用户输入computed 当方法调用computed 当属性用不加括号watch 监听对象没加 deep对象内部变化监听不到加{ deep: true }reactive 整个替换会丢失响应式只能改属性v-model 用在自定义组件默认绑 modelValue事件是 update:modelValuev-show 不支持 templatev-show 只能用在元素上不能用在 template
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →