Vue初探 MVVM模型 通常情况下,我们也经常称Vue是一个MVVM的框架,Vue官方其实有说明,Vue虽然并没有完全遵守MVVM的模型,但是整个设计是受到它的启发的。
引入方法 方法一:CDN引入
1 2 3 4 5 6 7 8 9 10 11 12 13 <div id ="app" > </div > <script src ="https://unpkg.com/vue@next" > </script > <script > const app = Vue .createApp ({ template : `<h2>Hello World</h2><span>呵呵呵</span>` }) app.mount ("#app" ) </script >
方法二:
1 2 3 4 5 6 7 8 9 10 11 12 13 <script src ="./lib/vue.js" > </script > <script > const app = Vue .createApp ({ template : `<h1>Hello Vue</h1>` }) app.mount ("#app" ) </script >
data属性 data是一个函数
data属性是传入一个函数,并且该函数需要返回一个对象。在Vue3.x的时候,必须传入一个函数(vue2可以传入对象),否则就会直接在浏览器中报错;
data中返回的对象会被Vue的响应式系统劫持,之后对该对象的修改或者访问都会在劫持中被处理:所以我们在template或者app中通过 访问counter,可以从对象中获取到数据;所以我们修改counter的值时,app中的 也会发生改变;
method属性 methods属性是一个对象,通常我们会在这个对象中定义很多的方法:
这些方法可以被绑定到 模板中;
在该方法中,我们可以使用this关键字来直接访问到data中返回的对象的属性;
1 2 3 title: 为什么不能使用箭头函数? 我们在methods中要使用data返回对象中的数据,这个this是必须有值的,并且应该可以通过this获取到data返回对象中的数据。 那么我们这个this能不能是window呢?不可以是window,因为window中我们无法获取到data返回对象中的数据;但是如果我们使用箭头函数,那么这个this就会是window了;为什么是window呢?这里涉及到箭头函数使用this的查找规则,它会在自己的上层作用于中来查找this;最终刚好找到的是script作用于中的this,所以就是window;
1 2 3 title: this到底指向什么? Vue的源码当中就是对methods中的所有函数进行了遍历,并且通过bind绑定了this: 
模板语法 mustache 插值语法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <h2 > {{ message }}</h2 > <h2 > 当前计数: {{ counter }} </h2 > <h2 > 计数双倍: {{ counter * 2 }}</h2 > <h2 > 展示的信息: {{ info.split(" ") }}</h2 > <h2 > {{ age >= 18? "成年人": "未成年人" }}</h2 > <h2 > {{ formatDate(time) }}</h2 >
v-once v-once用于指定元素或者组件只渲染一次, 当数据发生变化时,元素或者组件以及其所有的子元素将视为静态内容并且跳过,该指令可以用于性能优化。
如果是子节点,也是只会渲染一次。
1 2 3 4 <h2 v-once > {{ message }} <span > 数字: {{counter}}</span > </h2 >
v-text 用于更新元素的textContent
1 2 3 <span v-text ="msg" > </span > <span > {{ msg }}</span >
v-html 默认情况下,如果我们展示的内容本身是 html 的,那么vue并不会对其进行特殊的解析,如果我们希望这个内容被Vue可以解析出来,那么可以使用 v-html 来展示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <div id ="app" > <h2 > {{ content }}</h2 > <h2 v-html ="content" > </h2 > </div > <script src ="../lib/vue.js" > </script > <script > const app = Vue .createApp ({ data : function ( ) { return { content : `<span style="color: red; font-size: 30px;">哈哈哈</span>` } }, }) app.mount ("#app" ) </script >
v-pre v-pre用于跳过元素和它的子元素的编译过程,显示原始的Mustache标签,跳过不需要编译的节点,加快编译的速度
1 2 3 <div v-pre > <h2 > {{ message }}</h2 > </div >
v-cloak 保持在元素上直到关联组件实例结束编译
和 CSS 规则如[v-cloak] { display: none }一起用时,这个指令可以隐藏未编译的 Mustache 标签直到组件实例准备完毕
v-bind 动态绑定元素属性
1 <img :src ="showImgUrl" alt ="" >
动态绑定class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 <div id ="app" > <h2 :class ="classes" > Hello World</h2 > <button :class =" isActive ? 'active': '' " @click ="btnClick" > 我是按钮</button > <button :class ="{ active: isActive }" @click ="btnClick" > 我是按钮</button > <button :class ="{ active: isActive, why: true, kobe: false }" @click ="btnClick" > 我是按钮</button > <button class ="abc cba" :class ="{ active: isActive, why: true, kobe: false }" @click ="btnClick" > 我是按钮</button > <button class ="abc cba" :class ="getDynamicClasses()" @click ="btnClick" > 我是按钮</button > <h2 :class ="['abc', 'cba']" > Hello Array</h2 > <h2 :class ="['abc', className]" > Hello Array</h2 > <h2 :class ="['abc', className, isActive? 'active': '']" > Hello Array</h2 > <h2 :class ="['abc', className, { active: isActive }]" > Hello Array</h2 > </div > <script src ="../lib/vue.js" > </script > <script > const app = Vue .createApp ({ data : function ( ) { return { classes : "abc cba nba" , isActive : false , className : "why" } }, methods : { btnClick : function ( ) { this .isActive = !this .isActive }, getDynamicClasses : function ( ) { return { active : this .isActive , why : true , kobe : false } } } }) app.mount ("#app" ) </script >
绑定style
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <div id ="app" > <h2 style ="color: red; font-size: 30px;" > 哈哈哈哈</h2 > <h2 v-bind:style ="{ color: fontColor, fontSize: fontSize + 'px' }" > 哈哈哈哈</h2 > <h2 :style ="objStyle" > 呵呵呵呵</h2 > <h2 :style ="[objStyle, { backgroundColor: 'purple' }]" > 嘿嘿嘿嘿</h2 > </div > <script src ="../lib/vue.js" > </script > <script > const app = Vue .createApp ({ data : function ( ) { return { fontColor : "blue" , fontSize : 10 , objStyle : { fontSize : '50px' , color : "green" } } }, }) app.mount ("#app" ) </script >
绑定属性名
1 2 3 4 5 6 7 8 <h2 : [name ]="'aaaa'" > Hello World</h2 > data: function() { return { name: "class" } },
绑定对象
1 2 3 4 <h2 :name ="name" :age ="age" :height ="height" > Hello World</h2 > <h2 v-bind ="infos" > Hello Bind</h2 >
1 2 3 4 5 6 7 8 9 data : function ( ) { return { infos : { name : "why" , age : 18 , height : 1.88 , address : "广州市" }, name : "why" , age : 18 , height : 1.88 } },
事件绑定 基本操作 v-on指令用来监听事件
基本写法(直接写v-on的写法不再举例)
1 <div class ="box" @click ="divClick" > </div >
也可以写成一个表达式(不推荐)
1 <button @click ="counter++" > +1</button >
绑定其他方法
1 <div class ="box" @mousemove ="divMousemove" > </div >
绑定多个事件直接写上就行
1 <div class ="box" @click ="divClick" @mousemove ="divMousemove" > </div >
方法:
1 2 3 4 5 6 7 8 9 divClick ( ) { console .log ("divClick" ) }, increment ( ) { this .counter ++ }, divMousemove ( ) { console .log ("divMousemove" ) }
参数传递 默认传递event对象
1 <button @click ="btn1Click" > 按钮1</button >
1 2 3 btn1Click (event ) { console .log ("btn1Click:" , event) },
自定义参数
1 <button @click ="btn2Click('why', age)" > 按钮2</button >
1 2 3 btn2Click (name, age ) { console .log ("btn2Click:" , name, age) },
自定义参数和event对象
1 <button @click ="btn3Click('why', age, $event)" > 按钮3</button >
1 2 3 btn3Click (name, age, event ) { console .log ("btn3Click:" , name, age, event) }
带有修饰符的事件 支持修饰符
.stop - 调用 event.stopPropagation()。
.prevent - 调用 event.preventDefault()。
.capture - 在捕获模式添加事件监听器。
.self - 只有事件从元素本身发出才触发处理函数。
.{keyAlias} - 只在某些按键下触发处理函数。
.once - 最多触发一次处理函数。
.left - 只在鼠标左键事件触发处理函数。
.right - 只在鼠标右键事件触发处理函数。
.middle - 只在鼠标中键事件触发处理函数。
.passive - 通过 { passive: true } 附加一个 DOM 事件。
1 <button @click.stop ="btnClick" >按钮</button>
条件渲染 v-if v-else v-if-else v-if 个人信息存在就显示
1 2 3 4 5 6 7 <div class ="info" v-if ="Object.keys(info).length" > <h2 > 个人信息</h2 > <ul > <li > 姓名: {{info.name}}</li > <li > 年龄: {{info.age}}</li > </ul > </div >
v-if 和 v-else
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <div id ="app" > <div class ="info" v-if ="Object.keys(info).length" > <h2 > 个人信息</h2 > <ul > <li > 姓名: {{info.name}}</li > <li > 年龄: {{info.age}}</li > </ul > </div > <div v-else > <h2 > 没有输入个人信息</h2 > <p > 请输入个人信息后, 再进行展示~</p > </div > </div >
合起来用
1 2 3 4 5 6 <div id ="app" > <h1 v-if ="score > 90" > 优秀</h1 > <h2 v-else-if ="score > 80" > 良好</h2 > <h3 v-else-if ="score >= 60" > 及格</h3 > <h4 v-else > 不及格</h4 > </div >
template的使用 把要写的信息放在template中,根据条件渲染。最终template不会被渲染出来,但是template里面的元素会被渲染出来。
有点类似于小程序中的block
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <template v-if ="Object.keys(info).length" > <h2 > 个人信息</h2 > <ul > <li > 姓名: {{info.name}}</li > <li > 年龄: {{info.age}}</li > </ul > </template > <template v-else > <h2 > 没有输入个人信息</h2 > <p > 请输入个人信息后, 再进行展示~</p > </template >
v-show和v-if 的区别 v-show也是隐藏元素的一种方法,用法和v-if完全一样
首先,在用法上的区别:
v-show是不支持template;
v-show不可以和v-else一起使用;
其次,本质的区别:
v-show元素无论是否需要显示到浏览器上,它的DOM实际都是有存在的,只是通过CSS的display属性来进行切换;
v-if当条件为false时,其对应的原生压根不会被渲染到DOM中;
开发中如何进行选择?
如果我们的原生需要在显示和隐藏之间频繁的切换,那么使用v-show;
如果不会频繁的发生切换,那么使用v-if;
列表渲染 基本使用 v-for的基本格式是 “item in 数组”:
数组通常是来自data或者prop,也可以是其他方式;
item是我们给每项元素起的一个别名,这个别名可以自定来定义;
电影列表的渲染
1 2 3 <ul > <li v-for ="movie in movies" > {{ movie }}</li > </ul >
我们知道,在遍历一个数组的时候会经常需要拿到数组的索引:
如果我们需要索引,可以使用格式: “(item, index) in 数组”;
注意上面的顺序:数组元素项item是在前面的,索引项index是在后面的;
带有索引的渲染
1 2 3 4 <ul > <li v-for ="(movie, index) in movies" > {{index + 1}} - {{ movie }}</li > </ul >
v-for也支持遍历对象,并且支持有一二三个参数:
一个参数: “value in object”;
二个参数: “(value, key) in object”;
三个参数: “(value, key, index) in object”;
v-for同时也支持数字的遍历:每一个item都是一个数字;
v-for也可以遍历其他可迭代对象(Iterable)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <ul > <li v-for ="(value, key, index) in info" > {{value}}-{{key}}-{{index}}</li > </ul > <ul > <li v-for ="item in message" > {{item}}</li > </ul > <ul > <li v-for ="item in 100" > {{item}}</li > </ul >
列表渲染中的key有什么用? 官方解释:
key属性主要用在Vue的虚拟DOM算法,在新旧nodes对比时辨识VNodes;
如果不使用key,Vue会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用相同类型元素的算法;
而使用key时,它会基于key的变化重新排列元素顺序,并且会移除/销毁key不存在的元素
1 2 3 title:什么是VNode? 关于这个问题和虚拟DOM相关的算法,可以接着看视频: 第/974/975/集,有相关的解释
使用template 类似于v-if,你可以使用 template 元素来循环渲染一段包含多个元素的内容 – 我们使用template来对多个元素进行包裹,而不是使用div来完成;
这样使用的前提是div是没有意义的。
1 2 3 4 5 <template v-for ="(value, key, index) in infos" > <span > {{value}}</span > <strong > {{key}}</strong > <i > {{index}}</i > </template >
数组更新检测 Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新
这些被包裹过的方法包括:
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
也即是说,通过这些方法修改了原来的数组的时候,对应的视图也会随之更新。
但是,不修改原数组的方法不会引起视图的更新:
1 2 3 4 const newNames = this .names .map (item => item + "why" )this .names = newNames
计算属性 比较和使用 ==插值语法==:
1 2 3 <h2 > {{ firstName + " " + lastName }}</h2 > <h2 > {{ score >= 60 ? '及格': '不及格' }}</h2 > <h2 > {{ message.split(" ").reverse().join(" ") }}</h2 >
优点:适合简单的运算 缺点:如果多个地方用到,就会有大量重复的代码
==函数==:
1 2 3 <h2 > {{ getFullname() }}</h2 > <h2 > {{ getScoreLevel() }}</h2 > <h2 > {{ reverseMessage() }}</h2 >
优点:简洁 缺点:所有对的data使用过程变成了函数调用
==计算属性==:
用法:是一个属性,一个对象, 而不是函数。
选项:computed 类型:{ [key: string]: Function | { get: Function, set: Function } }
1 2 3 4 5 6 <h2 > {{ fullname }}</h2 > <h2 > {{ scoreLevel }}</h2 > <h2 > {{ reverseMessage }}</h2 >
1 2 3 4 5 6 7 8 9 10 11 12 computed : { fullname ( ) { return this .firstName + " " + this .lastName }, scoreLevel ( ) { return this .score >= 60 ? "及格" : "不及格" }, reverseMessage ( ) { return this .message .split (" " ).reverse ().join (" " ) } }
计算属性和方法的区别 计算属性会基于它们的依赖关系进行缓存;
在数据不发生变化时,计算属性是不需要重新计算的;
但是如果依赖的数据发生变化,在使用时,计算属性依然会重新进行计算;
计算属性set和get的写法 计算属性,计算属性,说到底还是属性 ,是一个属性,就是可以用this点出来,可以访问,也可以修改
此前我们使用的是函数式的写法,实际上是一个语法糖,事实上我们可以写成一个属性。
1 <button @click ="setFullname" > 设置fullname</button >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 computed : { fullname : { get : function ( ) { return this .firstname + " " + this .lastname }, set : function (value ) { const names = value.split (" " ) this .firstname = names[0 ] this .lastname = names[1 ] } } }, methods : { setFullname ( ) { this .fullname = "kobe bryant" } }
watch侦听 watch入门 watch是属性
开发中我们在data返回的对象中定义了数据,这个数据通过插值语法等方式绑定到template中,当数据变化时,template会自动进行更新来显示最新的数据,但是在某些情况下,我们希望在代码逻辑中监听某个数据的变化,这个时候就需要用侦听器watch来完成了;
侦听器的用法如下:
选项:watch
类型:{ [key: string]: string | Function | Object | Array}
侦听器默认侦听属性的值,对于对象,默认侦听引用的变化,如果要侦听对象内部属性的变化,需要写上deep属性,举例如下:
1 2 3 4 <div id ="app" > <h2 > {{message}}</h2 > <button @click ="changeMessage" > 修改message</button > </div >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 data ( ) { return { message : "Hello Vue" , info : { name : "why" , age : 18 } } }, methods : { changeMessage ( ) { this .message = "你好啊, 李银河!" , this .info = { name : "kobe" } } }, watch : { message (newValue, oldValue ) { console .log ("message数据发生了变化:" , newValue, oldValue) }, info (newValue, oldValue ) { console .log (this .info ); } }
侦听相关选项 ==深度监听&第一次渲染时执行一次监听器==
默认不会监听对象内部的属性,使用deep属性将会进行深度监听
也可以针对属性进行监听
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 watch : { info : { handler (newValue, oldValue ) { console .log ("侦听到info改变:" , newValue, oldValue) console .log (newValue === oldValue) }, deep : true , immediate : true }, "info.name" : function (newValue, oldValue ) { console .log ("name发生改变:" , newValue, oldValue) } }
this.$watch 我们可以在created的生命周期(后续会讲到)中,使用 this.$watchs 来侦听;
第一个参数是要侦听的源;
第二个参数是侦听的回调函数callback;
第三个参数是额外的其他选项,比如deep、immediate;
1 2 3 4 5 6 7 8 9 10 created ( ) { console .log ("created" )this .$watch("message" , (newValue, oldValue ) => { console .log ("message数据变化:" , newValue, oldValue) }, { deep : true }) }
v-model双向绑定 v-model指令可以在表单 input、textarea以及select元素上创建双向数据绑定;
它会根据控件类型自动选取正确的方法来更新元素,v-model 本质是语法糖,它负责监听用户的输入事件来更新数据,并在某种极端场景下进行一些特殊处理。
v-model绑定 略
v-model修饰符 ==lazy==
默认情况下,v-model在进行双向绑定时,绑定的是input事件,那么会在每次内容输入 后就将最新的值和绑定的属性进行同步
如果我们在v-model后跟上lazy修饰符,那么会将绑定的事件切换为 change 事件,只有在提交时 (比如回车)才会触发
1 2 3 <!-- 1. lazy : 绑定change事件 --> <input type ="text" v-model.lazy ="message" > <h2 > message: {{message}}</h2 >
==number==
v-model绑定的值总是string类型的,即使我们设置type为number类型(我们在进行逻辑判断的时候,如果是一个string类型,会进行隐式转换)。
如果我们希望转换为数字类型,那么可以使用 .number 修饰符
1 2 <input type ="text" v-model.number ="counter" >
==去除首尾空格==
1 <input type ="text" v-model.trim ="content" >
==使用多个修饰符==
1 <input type ="text" v-model.lazy.trim ="content" >
组件化开发入门
全局组件:在任何其他的组件中都可以使用的组件;
局部组件:只有在注册的组件中才能使用的组件;
全局组件的注册 全局组件需要使用我们全局创建的app来注册组件;
通过component方法传入组件名称、组件对象即可注册一个全局组件了;
之后,我们可以在App组件的template中直接使用这个全局组件:
全局组件的特点: 一旦注册成功后, 可以在任意其他组件的template中使用,也就是说,如果我们先注册了header,再注册了nav,那么我们可以在nav中使用header。理解起来很简单,根组件app是最后注册的,也就是说我们可以在根组件app中使用各种注册的组件。
==全局组件==
最终渲染位置
1 2 3 4 5 6 7 8 <div id ="app" > <product-item > </product-item > <product-item > </product-item > <product-item > </product-item > </div >
组件模版
1 2 3 4 5 6 7 8 9 <template id ="item" > <div class ="product" > <h2 > 我是商品</h2 > <div > 商品图片</div > <div > 商品价格: <span > ¥9.9</span > </div > <p > 商品描述信息, 9.9秒杀</p > </div > </template >
全局组件的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const App = {}const app = Vue .createApp (App )app.component ("product-item" , { template : "#item" }) app.mount ("#app" )
==组件自己的逻辑==
组件模版
1 2 3 4 5 6 7 8 <template id ="product" > <div class ="product" > <h2 > {{title}}</h2 > <p > 商品描述, 限时折扣, 赶紧抢购</p > <p > 价格: {{price}}</p > <button @click ="favarItem" > 收藏</button > </div > </template >
组件逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 app.component ("product-item" , { template : "#product" , data ( ) { return { title : "我是商品Item" , price : 9.9 } }, methods : { favarItem ( ) { console .log ("收藏了当前的item" ) } } })
组件的名称 方式一:使用kebab-case(短横线分割符)
当使用 kebab-case (短横线分隔命名) 定义一个组件时,你也必须在引用这个自定义元素时使用 kebab-case,例如 <my-component-name>
1 2 3 app.component ("my-component-name" , { })
1 <my-component-name > </my-component-name >
方式二:使用PascalCase(驼峰标识符)
当使用 PascalCase (首字母大写命名) 定义一个组件时,你在引用这个自定义元素时两种命名法都可以使用。
也就是说 <my-component-name> 和 <MyComponentName> 都是可接受的;
1 2 3 app.component ("MyComponentName" , { })
1 2 3 <my-component-name > </my-component-name > <MyComponentName > </MyComponentName >
注册局部组件 注册组件但不使用的时候,在构建项目的时候仍然会进行打包,因此我们在使用组件的时候通常选择局部注册。
局部注册是在我们需要使用到的组件中,通过components属性选项来进行注册;
比如之前的App组件中,我们有data、computed、methods等选项了,事实上还可以有一个components选项;
该components选项对应的是一个对象,对象中的键值对是 组件的名称: 组件对象;
组件中也可以继续注册组件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <div id ="app" > <home-nav > </home-nav > <product-item > </product-item > <product-item > </product-item > <product-item > </product-item > </div > <template id ="product" > <div class ="product" > <h2 > {{title}}</h2 > <p > 商品描述, 限时折扣, 赶紧抢购</p > <p > 价格: {{price}}</p > <button > 收藏</button > </div > </template > <template id ="nav" > <div > -------------------- nav start ---------------</div > <h1 > 我是home-nav的组件</h1 > <product-item > </product-item > <div > -------------------- nav end ---------------</div > </template >
组件注册
1 2 3 4 5 6 7 8 9 components : {ProductItem ,HomeNav : { template : "#nav" , components : { ProductItem } } },
SFC开发模式 在真实开发中,我们可以通过一个后缀名为 .vue 的single-file components (单文件组件) 来解决,并且可以使用webpack或者vite或者rollup等构建工具来对其进行处理
==如何支持SFC==
方式一:使用Vue CLI来创建项目,项目会默认帮助我们配置好所有的配置选项,可以在其中直接使用.vue文件;
方式二:自己使用webpack或rollup或vite这类打包工具,对其进行打包处理
安装和使用 全局安装
升级vue-cli
通过命令创建
创建项目的过程-Vue-Cli
==项目的目录结构==
创建项目的过程-Npm vue-cli创建的项目默认是使用webpack进行管理的,npm创建的项目默认使用vite进行管理。
创建过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 PS D:\code\github\workspace\vue> npm init vue@latest Need to install the following packages: create-vue@3.6.1 Ok to proceed? (y) y Vue.js - The Progressive JavaScript Framework √ Project name: ... vue-project √ Add TypeScript? ... No / Yes √ Add JSX Support? ... No / Yes √ Add Vue Router for Single Page Application development? ... No / Yes √ Add Pinia for state management? ... No / Yes √ Add Vitest for Unit Testing? ... No / Yes √ Add an End-to-End Testing Solution? » No √ Add ESLint for code quality? ... No / Yes Scaffolding project in D:\code\github\workspace\vue\vue-project... Done. Now run: cd vue-project npm install npm run dev
创建成功的项目默认通过vite打包。
配置webpack属性 在vue.config.js中配置相关属性,例如配置别名的时候:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const { defineConfig } = require ('@vue/cli-service' )module .exports = defineConfig ({ transpileDependencies : true , configureWebpack : { resolve : { alias : { "utils" : "@/utils" } } } })
在导出的模块中配置configWebpack属性,其中@是vue-cli内部已经配置好的路径别名,指src
jsconfig.json 作用: 给VSCode来进行读取, VSCode在读取到其中的内容时, 给我们的代码更加友好的提示.
在我们自定义路径的别名之后,vscode不认识我们的别名,导致我们在写路径的时候vscode不会给出提示。
在jsconfig中配置了相关信息之后,ide会根据我们配置的路径自动寻找文件给出提示
如图,我们配置了utils别名,当把别名配置到jsconfig中的时候,ide就有了utils目录下提示了。
引入的vue的版本
来自:1004–day57_jsconfig-Vue版本-组件间通信-插槽_02_(了解)Vue不同版本对template的处理
默认vue版本: runtime, vue-loader完成template的编译过程
vue.esm-bundler: runtime + compile, 对template进行编译
补充 单文件Vue style是有自己的作用域
style -> scoped
1 2 3 <style scoped > </style >
vite创建一个Vue项目