ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

不用Webpack的Vue:CDN引入、模板语法与响应式开发入门

不用Webpack的Vue:CDN引入、模板语法与响应式开发入门 提到Vue现在很多人第一反应就是脚手架、Webpack/Vite那一套。但我今天想聊的是另一种打开方式——不使用Webpack的Vue传统前端使用方式。也就是直接把Vue当做一个普通的JS库来用在HTML里用script标签引进来就开干。这种玩法在如今构建工具满天飞的环境下听起来确实有点“复古”但它真的不是过时而是很多场景下的最优解。刚接触Vue的朋友被各种工具链绕得头晕眼花配置环境的时间比写代码还长。而有经验的开发者也知道不是所有项目都需要一套完整工程化体系。这篇我先讲最基础的部分怎么引入Vue、怎么创建一个最简单的实例、怎么写模板语法、怎么处理事件和样式。这些是整个系列的地基也是后续深入组合式API、组件化开发的前提。把基础打牢你后面看任何Vue代码都不会发怵。1. 缘起为什么还要聊一个“老掉牙”的话题1.1 现代构建流程的复杂度问题这几年前端开发的“工程化”确实成熟了但也把不少初学者挡在了门外。记得我最早接触Vue时按教程走第一步就是装Node.js然后全局安装脚手架再执行创建命令。中间遇到权限问题、网络超时、版本冲突光环境就折腾了两三天真正写Vue代码的时间几乎为零。那种挫败感很多人应该体会过。而且构建工具本身也在不断演进。今天你用Webpack配置了一大堆东西明天可能社区就推荐Vite了。但无论工具怎么变Vue的核心概念——响应式数据、模板指令、组件这些从来没变过。不通过构建工具直接在浏览器里跑Vue恰恰能让这些核心概念以最直白的方式呈现出来。说白了工具是为解决问题服务的而不是反过来。如果只是做一个活动页、一个课程表小程序、一个后台系统的局部交互模块非要上一套完整的工程化体系反而是本末倒置。1.2 传统引入方式的适用场景那什么样的情况适合这种传统方式我盘点了一下大概有这么几类公司老项目里要局部引入Vue做交互比如给原有的服务端模板页面加上实时筛选、动态表格。个人练手做小demo验证一个想法或者写点学习笔记。后端同学一个人想搞定一个带简单交互的内部工具不想折腾node环境。某些部署环境限制多不能随意跑构建命令但可以直接放静态文件。其实还有一个很实际的原因加载速度快。CDN上的Vue文件本身就是压缩好的直接引入没有任何打包和转换过程。对于简单页面来说首屏性能可能比你引一堆按需加载的模块还要好。这个系列我打算用几篇文章把这种传统Vue开发方式从入门到进阶完整过一遍。作为第一篇先把地基打好。补充一句本文的示例代码都能直接在浏览器里跑不需要任何命令行操作。你只需要准备一个文本编辑器和一个浏览器就够了。2. 环境准备与引入Vue2.1 CDN引入与本地文件引入之争在传统方式下引入Vue就两种做法一种是直接用script标签引用CDN地址另一种是下载一个Vue的JS文件放到项目目录里。CDN方式最简单几行代码搞定!-- 开发版包含完整警告和辅助调试工具适合学习阶段 -- script srchttps://cdn.jsdelivr.net/npm/vue2/dist/vue.js/script注意上面是Vue 2的写法。如果你用的是Vue 3标签路径略有不同后面会专门提到。这里我为什么要提Vue 2因为相当一部分传统项目和老代码库用的还是Vue 2而且很多开箱即用的UI框架在Vue 2下生态最稳定。学习传统开发方式时从Vue 2入手一天就能上手后续再看Vue 3也不会觉得困难。毕竟响应式的核心思想和模板机制是一脉相承的。本地文件方式也简单官网下载vue.js和vue.min.js两个文件放到js目录下页面里引用相对路径就行script src/js/vue.min.js/script两种方式怎么选我的建议是只要能联网优先用CDN。别问为什么省事。但要注意如果目标项目是在内网运行或者对首屏加载速度有极致要求那就下载到本地。下载到本地时记得开发时引vue.js有警告提示上线时引vue.min.js压缩版。2.2 开发版与生产版的差异Vue的JS文件官方分了开发版和生产版。差别主要在开发版会带上完整的警告信息、把所有的断言和提示逻辑都保留生产版则把这些全部压缩去掉体积小一大截。比如你在代码里写了不存在的属性开发版会立刻在控制台给你一条红色的警告提示哪个组件、哪个位置出了问题生产版呢悄悄忽略什么都不报。所以自己学习的时候一定用开发版。我以前见过一位同事上线后某个数据一直显示不出来排查了半天才发现生产版把警告都吞了要是开发时能看到警告一分钟就能定位问题。具体CDN地址可以根据版本去官方文档的安装页找到。记住一句话学的时候带警告部署的时候换压缩版这是两条铁律。2.3 创建第一个Vue实例hello world的又一个版本项目文件就三个一个HTML文件、一个JS文件或直接在HTML里写、引入Vue。我习惯把Vue逻辑单独放在一个app.js里HTML只负责结构。先看HTML!DOCTYPE html html langzh-CN head meta charsetUTF-8 titleVue传统方式入门/title /head body div idapp p{{ message }}/p /div script srchttps://cdn.jsdelivr.net/npm/vue2/dist/vue.js/script script srcapp.js/script /body /html再看app.jsvar app new Vue({ el: #app, data: { message: 你好Vue } });打开浏览器页面上就会显示“你好Vue”。核心就三行el指定Vue实例挂载到哪个DOM节点data里存放响应式数据{{ message }}把数据渲染到模板里。当你通过app.message 换个内容修改数据时页面会自动刷新不需要写任何DOM操作代码。这就是响应式最直观的体现。3. 模板语法花括号、指令和它们背后的逻辑3.1 Mustache插值把数据“放”进去上面用到的{{ message }}这种双花括号的写法在Vue里叫Mustache插值。它不只是放一个简单的变量里面可以写任何合法的JavaScript表达式注意是表达式不能是语句。p{{ number 1 }}/p p{{ message.split().reverse().join() }}/p p{{ isOK ? 条件为真 : 条件为假 }}/p这些写法都是允许的。但不要太离谱比如在插值里写一长串业务逻辑那就很糟糕了。模板的意义在于声明结构复杂的计算应该挪到后面要讲的计算属性里去。还有一个细节插值是正确的做HTML转义的。什么意思如果message的值是scriptalert(xss)/scriptVue在渲染时会把尖括号转成lt;和gt;直接当成字符串显示出来而不会去执行里面的脚本。这是安全底线千万别用不需要转义的v-html指令去渲染用户输入的内容。3.2 v-bind与v-model属性绑定的两种形态花括号插值只能作用于标签体里的文本内容如果你想动态绑定HTML标签上的属性比如href、class、style就得用指令。指令是Vue模板里以v-开头的那几个特殊属性。v-bind的作用就是动态绑定一个属性a v-bind:hreflinkUrl点击跳转/a这里的linkUrl是Vue实例data里的一个数据项。Vue会把它的值设置为href属性的最终值。这个指令太常用了所以Vue提供了非常流行的缩写——直接用冒号a :hreflinkUrl点击跳转/a初看可能会有点奇怪但习惯之后你会发现写代码效率高了不少。v-model则是专门用于表单元素的双向绑定。所谓双向指的不只是数据变化会更新页面页面上的用户输入也会反向同步到数据里。比如input typetext v-modelsearchText用户在输入框里敲的每一个字符都会实时同步到searchText这个数据上。这在以前的原生开发里要监听input事件再手动赋值现在一行指令搞定也体现了Vue数据驱动思想的意义——你只管维护数据DOM层的变化全交给框架。3.3 v-on事件绑定用户交互的入口有了数据绑定自然就需要事件处理。v-on用来绑定DOM事件同样有缩写用代替button v-on:clickhandleClick点击/button button clickhandleClick点击缩写写法/buttonhandleClick是Vue实例methods里定义的方法var app new Vue({ el: #app, data: { count: 0 }, methods: { handleClick: function() { this.count 1; } } });methods里的方法在Vue实例上可以直接通过this访问到data里的数据。这是传统方式写交互最核心的技能之一。你可能会想为什么不直接在v-on后面写个表达式其实也可以比如clickcount 1但复杂逻辑一定要提到methods里面去。模板里写逻辑越少越好。4. 响应式原理与数据驱动页面为什么能自己动4.1 为什么数据改了页面就更新Vue的响应式机制是它最核心的竞争力。在传统方式下这个机制在底层是怎么实现的以Vue 2为例它会把data里的每个属性都经过Object.defineProperty处理给属性加上getter和setter。当属性被读取时比如模板渲染Vue会记录谁在依赖这个属性当属性被修改时它就会通知所有依赖方去更新。打个比方这就好比一间教室里老师在黑板上写了个通知“明天下午三点开会”。同学们模板中的各个位置看到这个通知后都会记在备忘录里。老师后来又把通知改成“推迟到四点”只要改一次黑板所有记了备忘录的同学都会按新时间去执行不需要挨个通知。这正是Vue开发的思维模式你只需要修改数据界面上所有跟这个数据有关的部分都会自动跟着变化。4.2 data为什么推荐用函数返回既然提到了data就不得不提一个关键细节。对于最简单的Vue实例data可以是一个对象data: { message: hello }但在后面会遇到的组件定义里data就必须是一个函数返回一个新对象。这么设计是为了保证每个组件实例都持有自己独立的数据拷贝不会互相串味。这可能是很多初学者第一次写组件死活不更新数据的根源两个组件实例共享了同一个data对象。我建议从一开始就养成良好的习惯——即使是根实例也写成函数返回的形式data: function() { return { message: hello }; }传统方式的演示阶段不改问题不大但一旦过渡到组件协作这个习惯能帮你少踩很多坑。4.3 计算属性模板里少写逻辑的利器模板里写复杂表达式不仅看着乱每渲染一次还会重新计算一遍浪费性能。Vue为此提供了计算属性computed。它看起来像是一个方法但本质上是基于依赖缓存的属性。var app new Vue({ el: #app, data: { firstName: 张, lastName: 三 }, computed: { fullName: function() { return this.firstName this.lastName; } } });模板里直接用{{ fullName }}把拼接逻辑放在计算属性里清清楚楚。而且只要firstName和lastName没有变化多次访问fullName返回的都是缓存值不会重复执行函数体。理解缓存机制是区分老手和新手的标志之一。5. 条件渲染与列表渲染让页面结构和数据对齐5.1 v-if与v-show条件渲染的二选一开发过程中经常会遇到这种需求某个区块在特定条件下显示否则隐藏。Vue提供两条指令来处理v-if和v-show。两者的区别很多网上的文章都讲过。这里我用最real的经验总结v-if是真正的条件渲染为false时DOM位置上就是空的什么都不会渲染v-show则是用CSS的display来控制显隐元素始终存在于DOM中只是被隐藏了。基于这个区别选择依据就很清楚了如果这个条件在页面生命周期内几乎不会变或者切换频率极低用v-if能省下不必要的DOM渲染开销。如果元素频繁切换显示状态比如标签页切换、下拉菜单展开收起用v-show避免反复创建和销毁DOM的性能损耗。在实际项目里我一般默认用v-show除非该元素在初始渲染时就确实不需要出现或者加载成本很高。这个选择直接影响用户体验。5.2 v-for列表渲染的核心套路动态列表是每个前端项目里逃不掉的需求。Vue用v-for指令来实现。基本写法ul li v-foritem in items v-bind:keyitem.id{{ item.name }}/li /ul对应的数据data: { items: [ { id: 1, name: 苹果 }, { id: 2, name: 香蕉 }, { id: 3, name: 橘子 } ] }Vue会遍历items数组为每个元素生成一个li。在遍历时可以拿到两个参数值和索引li v-for(item, index) in items{{ index }} - {{ item.name }}/li这里的索引index是从0开始的常用于显示序号。v-for还可以用来遍历对象但实际开发中遍历数组占90%以上。另外注意v-for通常配合key使用这个属性极其重要。5.3 key属性的价值别小看它key是Vue虚拟DOM算法的锚点。简单说当数据顺序或内容变化时Vue需要知道哪些节点是移动了、哪些是新增的、哪些是删除的。如果没有keyVue只能靠索引去匹配很容易出现复用错乱尤其当列表包含有状态的子组件或表单输入时后果是数据更新了但界面显示的是旧内容。选择key值时尽量用业务上唯一的ID别用数组索引。为什么因为索引代表的是位置不是身份。比如删掉列表第一项后面所有项的索引都变了Vue会以为整个列表都变了性能变差同时还会引发选中状态错乱。一个经典的坑列表里每项有个输入框你删除了中间一项结果输入框里的内容错位了这就是不写key或乱写key的典型后遗症。6. 实操演练做一个可排序的课程筛选页面理论讲再多不如动手做一个能跑的例子。这节我们手写一个小页面把前面这些知识串起来。需求很简单给一组课程数据做筛选和排序。6.1 页面结构与样式还是老规矩一个HTML文件一个JS文件。先定义页面布局div idapp h3课程列表/h3 div 搜索关键词: input typetext v-modelkeyword 排序方式: select v-modelsortType option valuedefault默认/option option valuepriceAsc价格从低到高/option option valuepriceDesc价格从高到低/option /select /div ul li v-foritem in filteredList :keyitem.id {{ item.name }} - {{ item.price }}元 /li /ul p v-iffilteredList.length 0没有符合条件的课程/p /div这个HTML里我们用到了v-model绑定输入框和下拉框、v-for循环渲染、:key绑定唯一ID、v-if做空状态处理。全部是通过数据驱动的形态完成的。6.2 数据处理逻辑JS部分直接上完整代码var app new Vue({ el: #app, data: { keyword: , sortType: default, courses: [ { id: 1, name: JavaScript基础, price: 99 }, { id: 2, name: Vue实战入门, price: 129 }, { id: 3, name: CSS高级技巧, price: 79 }, { id: 4, name: Node.js服务端开发, price: 199 } ] }, computed: { filteredList: function() { var self this; var list self.courses.filter(function(item) { return item.name.indexOf(self.keyword) ! -1; }); if (self.sortType priceAsc) { list.sort(function(a, b) { return a.price - b.price; }); } else if (self.sortType priceDesc) { list.sort(function(a, b) { return b.price - a.price; }); } return list; } } });核心逻辑全都封装在filteredList这个计算属性里。先按关键词过滤再按价格排序。模板里不需要写任何复杂逻辑只需要引用filteredList即可。6.3 运行效果与优化点打开页面你会看到四个课程。在搜索框里输入“Vue”列表只会剩下“Vue实战入门”把排序方式切换为“价格从高到低”课程顺序会立刻反过来。全程没有任何DOM操作所有改变都是数据驱动的。为什么用computed而不是methods因为数据不变时计算属性有缓存搜索和排序的结果不需要重复计算。如果每次渲染都调用一个方法性能会白白浪费在一些很简单的运算上。这个案例还可以继续扩展加筛选分类、加分页、加数量统计等等。但核心模式已经展示出来了——数据和模板的声明式绑定加上计算属性的数据加工链路这就是传统方式最常见的开发思路。7. 常见问题排查与个人经验补充7.1 页面显示原始代码Vue没有生效刚接触时很容易遇到的麻烦把HTML打开模板上的{{ message }}原样出现在页面上就跟普通文本一样。排查思路按照优先级来浏览器控制台有没有报错如果提示Vue is not defined基本就是脚本没有成功加载。检查CDN地址是否能访问、是否因为网络原因被拦截。el选择器是否对应正确如果实例挂载的节点ID写错了Vue找不到挂载点同样不会生效。脚本引入顺序是否正确Vue的JS必须在app.js之前引入。因为app.js里用了new Vue()执行的时候如果Vue变量还不存在就直接报错停了。很多情况下最后一个顺序问题最隐蔽。HTML的script是按顺序加载的这种传统的依赖关系必须靠手动保证一定要在JS业务代码之前引入Vue本体。7.2 数据更新了但视图没变这种问题排查起来更让人头疼因为你已经修改了数据console里面打印也正常但界面上就是没变化。第一步控制台看Vue实例是否有警告信息。开发版Vue在数据异常时会给出提示比如增删数组元素这类操作Vue 2里需要特殊写法的。为什么因为之前提到的defineProperty机制对数组的新增索引、length变更等操作监听不到必须用Vue提供的方法来触发更新比如数组.push(...)、Vue.set等。传统方式下我建议data里的数组要变更时优先用push、splice这些数组方法而不是直接用arr[i] newValue这种索引赋值。否则视图可能不动你还一脸懵。7.3 使用浏览器开发者工具辅助定位用传统方式开发Vue浏览器插件工具会在页面里注入一个Vue面板可以实时查看某个实例的data、computed、methods等状态。在排查问题时非常好用。发现页面数据不对时我一般先打开这个面板看数据本身对不对判断问题到底出在“数据层”还是“渲染层”。如果数据是对的再看模板绑定如果数据本身就不对先修数据逻辑。这种分层排查的思路在复杂项目里能帮你节省一半的时间精力。7.4 老生在实践中的几点体会最后说点个人经验。用了快十年的Vue我很庆幸当年是先接触传统引入方式再学的构建工具。直接裸写Vue让我对组件化、响应式、模板生命周期都有更本质的理解而不是模板生成器的一个操作员只会复制粘贴。第一这种模式最适合练习“数据驱动思维”。没有额外脚手架干扰每次交互都要自己定义数据再把数据和模板绑定好。思考路径极其清晰。第二不要以为传统方式等于低效。配合阅读官方文档和API完全能写出结构优雅、性能达标的完整项目。很多老系统到今天还在使用类似方案维持着几百上千个页面。第三这系列后续我还打算讲讲Vue组件怎么写、自定义指令和插槽怎么用以及如何手写轮子实现一个轻量级状态管理方案。只要你把第一篇的底子打扎实了后面就是水到渠成的事。平时我写个人小工具或者做临时验证的时候都是直接拖一个Vue CDN链接进HTML连开项目都不会开。哪怕只是为了能快速验证一个想法掌握这种原汁原味的Vue开发玩法怎么算都不亏。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表