兜兜转转,又回到了前端开发!
易学易用,基于标准 HTML、CSS 和 JavaScript 构建,提供容易上手的 API 和一流的文档。
性能出色,经过编译器优化、完全响应式的渲染系统,几乎不需要手动优化。
灵活多变,丰富的、可渐进式集成的生态系统,可以根据应用规模在库和框架间切换自如。
使用 Node.js 安装 Vue !
npm create vue@latest
这一指令将会安装并执行 create-vue,它是 Vue 官方的项目脚手架工具。
npm init vue@latest
这样也行。
然后使用安装命令对下载下来的脚手架进行安装。
npm install
最后进入项目目录,让项目运行起来!
npm run dev
认识一个项目先从他的目录结构开始!
文件名 | 描述 |
---|---|
node_modules | Vue 项目的运行依赖文件夹 |
public | 资源文件夹 |
src | 源码文件夹 |
index.html | 入口 Html 文件 |
package.json | 信息描述文件 |
vite.config.js | Vue 配置文件 |
Vue 使用一种基于 HTML 的模板语法,使我们能够声明式地将其组件实例的数据绑定到呈现的 DOM 上。所有的 Vue 模板都是语法层面合法的 HTML,可以被符合规范的浏览器和 HTML 解析器解析。
在底层机制中,Vue 会将模板编译成高度优化的 JavaScript 代码。结合响应式系统,当应用状态变更时,Vue 能够智能地推导出需要重新渲染的组件的最少数量,并应用最少的 DOM 操作。
最基本的数据绑定形式是文本插值,它使用的是“Mustache”语法 (即双大括号):
template
<span>Message: {{ msg }}</span>
双大括号标签会被替换为相应组件实例中 msg
属性的值。同时每次 msg
属性更改时它也会同步更新。
至此,我们仅在模板中绑定了一些简单的属性名。但是 Vue 实际上在所有的数据绑定中都支持完整的 JavaScript 表达式:
template
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div :id="`list-${id}`"></div>
这些表达式都会被作为 JavaScript ,以当前组件实例为作用域解析执行。
在 Vue 模板内,JavaScript 表达式可以被使用在如下场景上:
v-
开头的特殊 attribute) attribute 的值中每个绑定仅支持单一表达式,也就是一段能够被求值的 JavaScript 代码。一个简单的判断方法是是否可以合法地写在 return
后面。
因此,下面的例子都是无效的:
template
<!-- 这是一个语句,而非表达式 -->
{{ var a = 1 }}
<!-- 条件控制也不支持,请使用三元表达式 -->
{{ if (ok) { return message } }}
可以在绑定的表达式中使用一个组件暴露的方法:
template
<time :title="toTitleDate(date)" :datetime="date">
{{ formatDate(date) }}
</time>
绑定在表达式中的方法在组件每次更新时都会被重新调用,因此不应该产生任何副作用,比如改变数据或触发异步操作。
模板中的表达式将被沙盒化,仅能够访问到有限的全局对象列表。该列表中会暴露常用的内置全局对象,比如 Math
和 Date
。
没有显式包含在列表中的全局对象将不能在模板内表达式中访问,例如用户附加在 window
上的属性。然而,你也可以自行在 app.config.globalProperties
上显式地添加它们,供所有的 Vue 表达式使用。
双大括号会将数据解释为纯文本,而不是 HTML。若想插入 HTML,你需要使用 v-html
指令
<p>Using text interpolation: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
这里我们遇到了一个新的概念。这里看到的 v-html
attribute 被称为一个指令。指令由 v-
作为前缀,表明它们是一些由 Vue 提供的特殊 attribute,你可能已经猜到了,它们将为渲染的 DOM 应用特殊的响应式行为。这里我们做的事情简单来说就是:在当前组件实例上,将此元素的 innerHTML 与 rawHtml
属性保持同步。
数据绑定的一个常见需求场景是操纵元素的 CSS class 列表和内联样式。因为 class
和 style
都是 attribute,我们可以和其他 attribute 一样使用 v-bind
将它们和动态的字符串绑定。但是,在处理比较复杂的绑定时,通过拼接生成字符串是麻烦且易出错的。因此,Vue 专门为 class
和 style
的 v-bind
用法提供了特殊的功能增强。除了字符串外,表达式的值也可以是对象或数组。
我们可以给 :class
(v-bind:class
的缩写) 传递一个对象来动态切换 class:
<div :class="{ active: isActive }"></div>
上面的语法表示 active
是否存在取决于数据属性 isActive
的正假值。
你可以在对象中写多个字段来操作多个 class。此外,:class
指令也可以和一般的 class
attribute 共存。举例来说,下面这样的状态:
const isActive = ref(true)
const hasError = ref(false)
配合以下模板:
<div
class="static"
:class="{ active: isActive, 'text-danger': hasError }"
></div>
渲染的结果会是:
<div class="static active"></div>
当 isActive
或者 hasError
改变时,class 列表会随之更新。举例来说,如果 hasError
变为 true
,class 列表也会变成 "static active text-danger"
。
绑定的对象并不一定需要写成内联字面量的形式,也可以直接绑定一个对象:
const classObject = reactive({
active: true,
'text-danger': false
})
<div :class="classObject"></div>
这将渲染:
<div class="active"></div>
我们也可以绑定一个返回对象的计算属性。这是一个常见且很有用的技巧:
const isActive = ref(true)
const error = ref(null)
const classObject = computed(() => ({
active: isActive.value && !error.value,
'text-danger': error.value && error.value.type === 'fatal'
}))
<div :class="classObject"></div>
<template>
<div v-bind="objectofAttrs">往来无白丁</div>
</template>
<script>
export default{
data(){
return{
objectofAttrs:{
id:'container',
class: 'wrapper'
}
}
}
</script>
用于条件性地渲染一块内容。这块内容只会在指令的表达式返回真值时才被渲染
v-if
指令用于条件性地渲染一块内容。
<h1 v-if="awesome">Vue is awesome!</h1>
v-else
也可以使用 v-else
为 v-if
添加一个“else 区块”。
<button @click="awesome = !awesome">Toggle</button>
<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
v-else-if
顾名思义,v-else-if
提供的是相应于 v-if
的“else if 区块”。它可以连续多次重复使用:
<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>
Not A/B/C
</div>
和 v-else
类似,一个使用 v-else-if
的元素必须紧跟在一个 v-if
或一个 v-else-if
元素后面。
另一个可以用来按条件显示一个元素的指令是 v-show
。其用法基本一样:
<h1 v-show="ok">Hello!</h1>
不同之处在于 v-show
会在 DOM 渲染中保留该元素;v-show
仅切换了该元素上名为 display
的 CSS 属性。
v-show
不支持在 <template>
元素上使用,也不能和 v-else
搭配使用。
v-if
是“真实的”按条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建。
v-if
也是惰性的:如果在初次渲染时条件值为 false,则不会做任何事。条件区块只有当条件首次变为 true 时才被渲染。
相比之下,v-show
简单许多,元素无论初始条件如何,始终会被渲染,只有 CSS display
属性会被切换。
总的来说,v-if
有更高的切换开销,而 v-show
有更高的初始渲染开销。因此,如果需要频繁切换,则使用 v-show
较好;如果在运行时绑定条件很少改变,则 v-if
会更合适。
我们可以使用 v-for
指令基于一个数组来渲染一个列表。v-for
指令的值需要使用 item in items
形式的特殊语法,其中 items
是源数据的数组,而 item
是迭代项的别名:
<script>
export default {
data(){
return {
goods:[
{title:"Air Jordan CMFT 11", price:603},
{title:"Nike ZoomX Invincible Run Flyknit 3", price:1135},
{title:"李宁 反伍二代", price:328},
{title:"Converse/匡威 1970s", price:299},
{title:"Nike Zoom Freak 3", price:839}
],
style_price:{
class: 'price',
}
}
}
}
</script>
<template>
<h3>Tish is a List!</h3>
<li v-for="good in goods">{{good.title}} <span v-bind="style_price">¥{{good.price}}</span></li>
</template>
<style>
.price{
color:orange;
font-style: italic;
font-weight: bold;
}
</style>
在 v-for
块中可以完整地访问父作用域内的属性和变量。v-for
也支持使用可选的第二个参数表示当前项的位置索引。
当然我们也可以用 of
来代替 in
进行相关循环
v-for
也可以遍历对象
<p v-for="(item,key,index) of userInfo">{{key}}|{{index}}|{{item}}</p>
v-for
可以直接接受一个整数值。在这种用例中,会将该模板基于 1...n
的取值范围重复多次。
<span v-for="n in 10">{{ n }}</span>
注意此处 n
的初值是从 1
开始而非 0
。
Vue 默认按照“就地更新”的策略来更新通过 v-for
渲染的元素列表。当数据项的顺序改变时,Vue 不会随之移动 DOM 元素的顺序,而是就地更新每个元素,确保它们在原本指定的索引位置上渲染。
默认模式是高效的,但只适用于列表渲染输出的结果不依赖子组件状态或者临时 DOM 状态 (例如表单输入值) 的情况。
为了给 Vue 一个提示,以便它可以跟踪每个节点的标识,从而重用和重新排序现有的元素,你需要为每个元素对应的块提供一个唯一的 key
attribute:
<div v-for="item in items" :key="item.id">
<!-- 内容 -->
</div>
当你使用 <template v-for>
时,key
应该被放置在这个 <template>
容器上:
<template v-for="todo in todos" :key="todo.name">
<li>{{ todo.name }}</li>
</template>
key
在这里是一个通过v-bind
绑定的特殊 attribute。请不要和在v-for
中使用对象里所提到的对象属性名相混淆。
推荐在任何可行的时候为 v-for
提供一个 key
attribute,除非所迭代的 DOM 内容非常简单 (例如:不包含组件或有状态的 DOM 元素),或者你想有意采用默认行为来提高性能。
key
绑定的值期望是一个基础类型的值,例如字符串或 number 类型。不要用对象作为 v-for
的 key。关于 key
attribute 的更多用途细节,请参阅 key API 文档。
我们可以使用 v-on
指令 (简写为 @
) 来监听 DOM 事件,并在事件触发时执行对应的 JavaScript。用法:v-on:click="handler"
或 @click="handler"
。
事件处理器 (handler) 的值可以是:
onclick
类似)。<script>
export default {
data(){
return {
clickCount: 0,
}
}
}
</script>
<template>
<button @click="clickCount++">😁Add Me~</button>
<p>The count is:{{clickCount}}</p>
</template>
随着事件处理器的逻辑变得愈发复杂,内联代码方式变得不够灵活。因此 v-on
也可以接受一个方法名或对某个方法的调用。
<script>
export default {
data(){
return {
clickCount: 0,
}
},
// 所有函数方法放这里
methods:{
addClick(){
this.clickCount = this.clickCount + 100;
}
}
}
</script>
<template>
<button @click="clickCount++">😁Add Me~</button>
<button @click="addClick">😁Add Me + 100~</button>
<p>The count is:{{clickCount}}</p>
</template>
我们可以使用 <script>
中的 methods
来在里面添加函数!
<script>
export default {
data(){
return {
clickCount: 0,
}
},
// 所有函数方法放这里
methods:{
removeClick(e){
this.clickCount = this.clickCount - 1;
e.target.innerHTML = '😅Add Me - ' + this.clickCount;
}
}
}
</script>
<template>
<button @click="removeClick">😅Add Me - 1~</button>
<p>The count is:{{clickCount}}</p>
</template>
在 Vue 中的 event 对象,就是原生JS的 Evet 对象
<script>
export default {
data(){
return {
goods:[{
"order_id": 1,
"goods_id": "43220",
"name": "Asics/亚瑟士 Gel-Flux 4 包裹性 舒适缓冲 跑鞋",
"price": "0",
"style_id": "46004336",
"style_name": "GS/白色/红色/蓝色",
},
{
"order_id": 7,
"goods_id": "5975629",
"name": "匹克 态极闪现6 低帮 减震支撑 防滑耐磨 回弹 篮球鞋",
"price": "389",
"style_id": "230837174",
"style_name": "开心果绿/贻贝绿",
},
{
"order_id": 8,
"goods_id": "6532",
"name": "New Balance 878 舒适百搭 防滑耐磨 缓震 网布透气 运动 复古 休闲鞋",
"price": "402",
"style_id": "4239338",
"style_name": "黑灰色",
},
{
"order_id": 9,
"goods_id": "462661",
"name": "Puma/彪马 Clyde Hardwood Team 缓震 篮球鞋",
"price": "281",
"style_id": "5333625",
"style_name": "纯白/黑色",
}]
}
},
methods: {
getGoodsDetail(good) {
alert("["+ good.style_name + "]" + good.name + "¥" + good.price)
}
}
}
</script>
<template>
<div>
<h3>商品清单</h3>
<p @click="getGoodsDetail(good)" v-for="good of goods" :key="good.goods_id">{{good.name}} | ¥ {{good.price}}</p>
</div>
</template>
<style>
</style>
直接使用 getGoodsDetail(good)
进行传参
如果想获取 event 对象,又想传参,这时候我们可以将上述代码稍作修改
<script>
export default {
data(){
return {
goods:[
{
"order_id": 9,
"goods_id": "462661",
"name": "Puma/彪马 Clyde Hardwood Team 缓震 篮球鞋",
"price": "281",
"style_id": "5333625",
"style_name": "纯白/黑色",
}]
}
},
methods: {
getGoodsDetail(good,e) {
alert("["+ good.style_name + "]" + good.name + "¥" + good.price)
}
}
}
</script>
<template>
<div>
<h3>商品清单</h3>
<p @click="getGoodsDetail(good,$event)" v-for="good of goods" :key="good.goods_id">{{good.name}} | ¥ {{good.price}}</p>
</div>
</template>
<style>
</style>
加入 $event
即可传入 event 对象!
在处理事件时调用 event.preventDefault()
或 event.stopPropagation()
是很常见的。尽管我们可以直接在方法内调用,但如果方法能更专注于数据逻辑而不用去处理 DOM 事件的细节会更好。
<script>
export default {
methods: {
getGoodsDetail(good) {
alert("["+ good.style_name + "]" + good.name + "¥" + good.price)
},
clickHandler(e) {
e.preventDefault()
console.log('click');
}
}
}
</script><template>
<div>
<h3>商品清单</h3>
<div v-for="good of goods" :key="good.goods_id">
<span>{{good.name}} | ¥ {{good.price}} .</span>
<a :href=good.goods_pic @click="clickHandler"><span style="color:green">Buy it!</span></a>
</div>
</div>
</template>
上面是外联模式,为解决这一问题,Vue 为 v-on
提供了事件修饰符。修饰符是用 .
表示的指令后缀,包含以下这些:
.stop
禁止冒泡(触发子元素,顺便把父元素也冒泡了).prevent
阻止默认事件.self
.capture
.once
.passive
<!-- 单击事件将停止传递 -->
<a @click.stop="doThis"></a>
<!-- 提交事件将不再重新加载页面 -->
<form @submit.prevent="onSubmit"></form>
<!-- 修饰语可以使用链式书写 -->
<a @click.stop.prevent="doThat"></a>
<!-- 也可以只有修饰符 -->
<form @submit.prevent></form>
<!-- 仅当 event.target 是元素本身时才会触发事件处理器 -->
<!-- 例如:事件处理器不来自子元素 -->
<div @click.self="doThat">...</div>
<div@click="clickDiv">
<p@click="clickP">测试冒泡</p>
</div>
<script>
methods:{
clickP(e){
e.stopPropagation();
console.log("p");
}
}
</script>
当然我们不想要他触发 stopPropagation
Vue能够侦听响应式数组的变更方法,并在它们被调用时触发相关的更新。
这些变更方法包括:
变更方法,顾名思义,就是会对调用它们的原数组进行变更。相对地,也有一些不可变 (immutable) 方法,例如 filter()
,concat()
和 slice()
,这些都不会更改原数组,而总是返回一个新数组。当遇到的是非变更方法时,我们需要将旧的数组替换为新的:
this.items = this.items.filter((item) => item.message.match(/Foo/))
你可能认为这将导致 Vue 丢弃现有的 DOM 并重新渲染整个列表——幸运的是,情况并非如此。Vue 实现了一些巧妙的方法来最大化对 DOM 元素的重用,因此用另一个包含部分重叠对象的数组来做替换,仍会是一种非常高效的操作。
<script>
export default {
data(){
return {
goods:[
{id:1,title:"Air Jordan CMFT 11", price:603},
{id:2,title:"Nike ZoomX Invincible Run Flyknit 3", price:1135},
{id:3,title:"李宁 反伍二代", price:328},
{id:4,title:"Converse/匡威 1970s", price:299},
{id:5,title:"Nike Zoom Freak 3", price:839}
]
}
},
methods: {
addProduct(){
//引起UI自动更新的方法
//this.goods.push({id:6,title:"361° 飞燃2.5ET", price:299})
//合并一个数组,不会让UI变化(只合并,不赋值)
this.goods.concat([{id:6,title:"361° 飞燃2.5ET", price:299},{id:7,title:"Under Armour/安德玛 Curry 9", price:479}])
console.log(this.goods)
}
}
}
</script>
<template>
<h3>数组变化监听</h3>
<button @click="addProduct">添加数据</button>
<ul>
<li v-for="good in goods" :key="good.id">{{good.title}}</li>
</ul>
</template>
模板中的表达式虽然方便,但也只能用来做简单的操作。如果在模板中写太多逻辑,会让模板变得臃肿,难以维护。比如说,我们有这样一个包含嵌套数组的对象:
export default {
data(){
return {
goods:[
{id:1,title:"Air Jordan CMFT 11", price:603},
{id:2,title:"Nike ZoomX Invincible Run Flyknit 3", price:1135},
{id:3,title:"李宁 反伍二代", price:328},
{id:4,title:"Converse/匡威 1970s", price:299},
{id:5,title:"Nike Zoom Freak 3", price:839},
{id:6,title:"361° 飞燃2.5ET", price:299},
{id:7,title:"Under Armour/安德玛 Curry 9", price:479}
]
}
}
}
我们想根据 goods
是否已有一些运动鞋来展示不同的信息:
<p>购物车是否有商品:</p>
<span>{{ goods.length > 0 ? 'Yes' : 'No' }}</span>
这里的模板看起来有些复杂。我们必须认真看好一会儿才能明白它的计算依赖于 goods
。更重要的是,如果在模板中需要不止一次这样的计算,我们可不想将这样的代码在模板里重复好多遍。
因此我们推荐使用计算属性来描述依赖响应式状态的复杂逻辑。这是重构后的示例:
<script>
export default {
data(){
return {
goods:[
{id:1,title:"Air Jordan CMFT 11", price:603},
{id:2,title:"Nike ZoomX Invincible Run Flyknit 3", price:1135},
{id:3,title:"李宁 反伍二代", price:328},
{id:4,title:"Converse/匡威 1970s", price:299},
{id:5,title:"Nike Zoom Freak 3", price:839},
{id:6,title:"361° 飞燃2.5ET", price:299},
{id:7,title:"Under Armour/安德玛 Curry 9", price:479}
]
}
},
computed:{
totalPrice(){
let total=0;
for(let i = 0; i < this.goods.length; i++){
total += this.goods[i].price;
}
return total;
}
}
}
</script>
<template>
<h3>🛒我的购物车</h3>
<ul>
<li v-for="god in goods" :key="god.id">{{god.title}} | <span style="color: orange">Price:¥{{god.price}}</span></li>
</ul>
<h4>Total: ¥{{totalPrice}}</h4>
</template>
可能注意到我们在表达式中像这样调用一个函数也会获得和计算属性相同的结果。
若我们将同样的函数定义为一个方法而不是计算属性,两种方式在结果上确实是完全相同的,然而,不同之处在于计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才重新计算。
重点区别:
计算属性:计算属性值会基于其响应式依赖被缓存。二个计算属性仅会在其响应式依赖更新时才重新计算
方法:方法调用总是会在重渲染发生时再次执行函数
Оптимальные цены на швейную фурнитуру оптом в Москве, заказывайте оптовые партии.
Купить швейную фурнитуру оптом http://www.sewingsupplies.ru/ .
Популярные мастерские по изготовлению серебряных колец в Саратове, которые станут украшением вашего стиля.
Купить кольцо серебро женское https://xn--b1acnbnotaei0k.xn--p1ai/ .
Лучшие стоматологические клиники в Минске, современными методиками, и стать обладателем здоровой улыбки.
Прейскурант цен стоматология http://belamed.ru/ .
Базальная имплантация зубов с гарантией качества.
Базальная имплантация цена https://www.belfamilydent.ru/services/basal-implantation/ .
Лучшие специалисты в Минске установят циркониевые коронки, обеспечат безупречный результат.
Поставить циркониевую коронку https://www.belfamilydent.ru/services/koronki-iz-cirkoniya .