兜兜转转,又回到了前端开发!
易学易用,基于标准 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>可能注意到我们在表达式中像这样调用一个函数也会获得和计算属性相同的结果。
若我们将同样的函数定义为一个方法而不是计算属性,两种方式在结果上确实是完全相同的,然而,不同之处在于计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才重新计算。
重点区别:
计算属性:计算属性值会基于其响应式依赖被缓存。二个计算属性仅会在其响应式依赖更新时才重新计算
方法:方法调用总是会在重渲染发生时再次执行函数
Get answer on your question by new non-criminal Blockchain Search Engine!
Free for use. We make money on advertising, making Blockchain entry - private (10$) and paid API.
Base ~200 mln valid domains.
Enter your request in latin and choose base - you will receive file with the occurrence of a substring in the domain
Link (own hosting): http://78.29.53.57/searchdomain/
http://78.29.53.57/searchdomain/
Пионы купить в Москве букет с доставкой на дом недорого
В столице есть огромное разнообразие магазинов, в которых можно приобрести пионы по выгодным тарифам.
博主你好,茶备案项目新开张,希望得到更大的支持加入茶备案!注册得到您的专属网站备案号!希望博主多多支持!https://icp.redcha.cn
希望博主能在我们网站申请一个备案号放在页脚呀!感谢博主的支持
无论赞助多少,或者是不赞助也好联系站长都可以,尽量给个靓号
如果被打扰了,那就万分抱歉