一、Vue概述
Vue语法高亮插件
VS Code默认不自带Vue高亮,需要安装官方插件:
插件名称:Vetur
Vue是一个采用mvvm模型(数据驱动视图)、用于构建用户界面的的渐进式javaScript框架。它基于标准HTML、CSS、javaScript构建,并提供了一套声明式、组件式的编程模型。内部采用了虚拟DOM(对象)和diff算法来进行相关的比对,减少了重绘和回流,提高了相关的性能。
易用:
-
渐进式:可以按需使用它的功能,不用一开始就引入所有模块。
-
声明式:只需要描述“想要什么结果”,不用关心“怎么实现”。
-
组件式:把页面拆分成独立、可复用、低耦合的小模块,每个组件包含自己的HTML(视图)、JS(逻辑)、CSS(样式),最后像“搭乐高”一样组合成完整页面。
高效:
-
虚拟DOM:用JavaScript对象来模拟真实DOM结构的 “副本”。
为什么Vue要用虚拟DOM? 真实DOM操作性能差:每次修改真实DOM会触发浏览器的“重绘/回流”,频繁操作会卡顿; 虚拟DOM是JS对象:操作JS对象的速度远快于操作真实DOM,Vue先在虚拟DOM上完成所有修改,再批量更新真实DOM,减少重绘/回流。
-
diff算法: Vue用来对比“新旧虚拟 DOM”差异的算法,它会遍历新旧虚拟DOM树,找出“哪些节点需要更新”,只更新有差异的部分,而不是全量替换。
二、Vue2和Vue3(面试题:重点是diff算法比较)
相关区别
数据劫持
Vue2底层采用了Object.defineProperty来进行数据劫持,由于需要指定所有的key,而数组不方便确定key,所以针对于数组,它通过重写数组更改本身的7个方法,来进行相关劫持操作。
Vue3底层采用了Proxy来进行数据劫持,不需要指定key,也就不需要递归,提高了对应的性能。
Proxy能直接监听对象属性的新增与删除、数组索引与长度的变化,无需像Vue2那样使用Vue.set等特殊方法,性能高且实现更简洁。
api设计
Vue2采用了Option Api(选项式Api),它内部设计为类的形式。
Vue3采用了Composition Api(组合式Api),它的设计是以工厂函数的形式来进行对象的实例化。
ts的兼容
Vue2对应ts的兼容性不好,它需要第三方插件的支持。
Vue3全面兼容ts,推荐Vue3代码结合ts进行项目开发。
编译和打包
Vue3在Vue2基础上,提供了静态标识,提高了编译速度。Vue3提供了tree Sharking来减少打包体积。
静态标识:编译时标记“静态节点”(如纯文本
<div>Hello</div>),只创建一次,后续更新跳过对比,编译速度提升。tree Sharking:基于ES Module模块化,打包时自动剔除未使用的 API(如未用watch则不打包相关代码),显著减小打包体积。
diff算法(面试重点)
核心区别就是Vue3的diff 算法在编译阶段做了更多准备(打标记、缓存静态节点),运行时只做最小化的对比,比Vue2更高效,尤其在大列表、复杂页面上,性能提升更明显。
Vue2的diff算法是基于启发式的双端比较算法。
双端比较:同时从新旧列表的【头部、尾部】向中间遍历,对比节点是否可复用(通过key)。
Vue3的diff算法是基于最长递增子序列的策略。
最长递增子序列:找到无需移动的节点序列,仅移动该序列外的节点。
Vue2是“全量 diff”,从头对比所有节点;Vue3加了 “补丁标记”,只对比可能变化的节点,更精准。
列表对比时,Vue3用“最长递增子序列”算法(LIS:贪心、二分),只移动需要改的元素,比Vue2的“按索引全改”效率高。
Vue3会缓存静态节点,diff时直接跳过,Vue2还会对比静态内容,做无用功。
贪心:小了就替换,大了就追加
二分:在有序 tails 里,用最少比较找到该替换的位置
注意:Vue3全面兼容Vue2的语法。
三、Vue入门
采用cdn的方式
Vue2的入门案例
<body>
<!-- Vue2 -->
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.2/vue.min.js"></script>
<div id="app">
<!-- 插值表达式 -->
{{msg}}
</div>
<script>
//Option Api,设计为类
let vm = new Vue({
//设置挂载点,自动挂载
el: "#app",
//设置数据
data: {
msg: "Vue2的基础使用"
}
})
</script>
</body>
插值表达式:一种特殊的模板语法,主要用于解析javaScript。
挂载点:不能是html标签和body标签。
Vue3的入门案例
<body>
<!-- Vue3 CDN 引用 -->
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.5.2/vue.global.min.js"></script>
<div id="app">
<!-- 插值表达式展示数据 -->
{{msg}}
</div>
<script>
// 使用Composition API创建Vue应用
let app = Vue.createApp({
// setup函数作为组合式API入口
setup() {
// 使用ref创建响应式数据
const msg = Vue.ref('Vue3的基础使用')
// 返回模板可访问的数据
return {
msg
}
}
})
// 将应用挂载到DOM元素
app.mount("#app")
</script>
</body>
采用脚手架的方式
Vue项目创建与初始化
使用以下命令通过不同方式创建 Vue 项目:
# 使用 Vite 创建项目
npm create vue@latest
# 使用 Webpack (基于 vue-cli)
vue create 项目名
# 通过图形化界面创建
vue ui
安装依赖与运行开发服务器
进入项目目录并安装依赖后启动开发服务器:
cd <your-project-name>
npm install
npm run dev
生产环境构建
生成生产环境构建文件(默认输出到 ./dist 目录):
npm run build
应用实例创建
每个 Vue 应用都需要通过 createApp 创建应用实例:
import { createApp } from 'vue'
const app = createApp({
// 根组件选项
})
根组件模板示例
DOM 中的模板示例(需与实例数据联动):
<div id="app">
<button @click="count++">{{ count }}</button>
</div>
完整初始化示例
结合模板与脚本的完整初始化js代码:
import { createApp } from 'vue'
const app = createApp({
data() {
return {
count: 0
}
}
})
app.mount('#app')
四、插值表达式
插值表达式是Vue中最基础的视图渲染方式,语法为{{ 表达式 }},核心作用是将数据动态渲染到页面。
-
支持算术运算
-
支持对应的javaScript语法
-
支持解析变量
-
不支持多语句表达式,只支持单语句表达式
基础语法
`{{javaScript代码}}`
示例
<body>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.2/vue.min.js"></script>
<div id="app">
<!-- 支持算法运算 -->
{{1+3}}
<!-- 支持对应的javaScript的语法 -->
{{"hello world".substring(1, 3)}}
<!-- 支持解析变量 -->
{{message}}
<!-- 不支持多语句表达式,只支持单语句表达式 -->
<!-- {{if(true){return "条件为真的值"}else{return "条件为假的值"}}} -->
</div>
<script>
let message = "你好,张三" //非响应式变量
new Vue({
el: "#app" //挂载点不能是html标签和body标签
})
</script>
</body>
Vue2和Vue3的区别
核心共性(两者完全一致)
-
基础语法规则:
都使用{{ }}包裹内容,且仅支持“有返回值的表达式”(比如算术运算、JS原生方法调用、变量取值),不支持if/for这类无返回值的语句。
-
响应式依赖:
插值中解析的变量必须绑定到Vue的响应式数据中(Vue2的data选项、Vue3的ref/reactive),普通JS变量无法触发视图更新。
-
挂载限制:
插值所在的根挂载节点都不能是
<html>或<body>标签,否则会导致渲染异常。 -
基础能力覆盖:
都支持算术运算(如{{ 1+2 }})、JS原生语法(如字符串截取、数组方法)、响应式变量解析(如{{ 用户名 }})。
核心差异(仅细节层面)
-
过滤器支持:
Vue2原生支持插值表达式搭配过滤器(如{{ 变量 | 过滤器名 }}),可直接在插值中对数据做格式化处理。
Vue3则移除了过滤器功能,需用方法或计算属性替代这一需求。
-
全局属性访问:两者在模板中访问全局属性的语法一致,但全局属性的挂载方式不同,对插值写法无影响。
Vue2挂载到Vue.prototype。
Vue3挂载到app.config.globalProperties。
-
底层性能优化:
Vue3对插值表达式做了静态提升优化——静态插值(如固定的算术运算结果)会被编译为常量,仅创建一次;动态插值会标记专属标识,仅对比变化的内容,性能优于Vue2。
而Vue2无此优化,所有插值都会参与每次的Diff对比。
-
组合式API适配:
Vue2仅支持Options API,插值变量只能来自data。
Vue3兼容Options API,同时支持setup中声明的ref/reactive变量(只需暴露给模板),但插值语法本身不变。
五、Vue的相关指令(面试题:5.2、5.4.1、5.4.2)
在vue中采用v-开头的相关属性为vue的指令。
5.1、v-text和v-html
-
v-text用于指定显示的文本(底层实现为innerText)。
-
v-html用于指定显示对应的html的代码(底层实现为innerHTML,需防范xss攻击)。
<body>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.2/vue.min.js"></script>
<div id="app">
<p v-text="text">这是我的内容</p>
<p v-html="htmlCode"></p>
</div>
<script>
new Vue({
el: "#app",
data: {
text: "hello",
htmlCode: "<h1>html代码</h1>"
}
})
</script>
</body>
相关指令内部传递的内容,其实也是一个类似于插值表达式的解析作用域。
v-text和插值表达式的区别: v-text会覆盖整个标签内的内容,插值表达式不会。
| 特性 | v-text | v-html |
|---|---|---|
| 内容解析方式 | 纯文本(不解析 HTML) | 解析 HTML 标签并渲染 |
| 安全风险 | 无(仅渲染文字) | 有(XSS 风险) |
| 等价写法 | {{ 变量 }} | 无直接等价插值写法 |
| 覆盖原有内容 | 是(覆盖元素内所有内容) | 是(覆盖元素内所有内容) |
5.2、v-if和v-show(面试题)
-
v-if:控制内容的渲染。当前条件为true就渲染 为false就不渲染。
-
v-show:指定当前的内容的显示隐藏。一定会渲染,它的隐藏是通过添加display:none来实现的。
<div id="app">
<h1 v-show="isShow">显示内容</h1>
<h1 v-show="!isShow">隐藏内容</h1>
<h1 v-if="isRender">v-if的内容</h1>
<h1 v-else-if="isRender">v-else-if的内容</h1>
<h1 v-else>v-else的内容</h1>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.2/vue.min.js"></script>
<script>
new Vue({
el: "#app",
data: {
isShow: true, //v-show
isRender: true //v-if
}
})
</script>
区别
v-if是控制内容的渲染,当值变化的时候可能会渲染多次或不渲染。适用于不需要频繁切换的情况。
v-show是控制内容的显隐,有且只会渲染一次。适用于频繁切换的情况。
| 特性 | v-if | v-show |
|---|---|---|
| 底层实现 | 控制DOM节点的渲染/移除 | 控制DOM节点的样式(display: none) |
| 渲染次数 | 条件变化时可能多次渲染(true 渲染、false 移除),也可能完全不渲染 | 有且仅渲染一次(初始化时就生成 DOM),后续仅切换显隐 |
| 性能开销 | 切换时(渲染/销毁)开销大 | 切换时(改样式)开销极小 |
| 适用场景 | 不需要频繁切换的场景(如权限控制、首次加载判断) | 需要频繁切换的场景(如 tab 切换、弹窗显隐) |
| 配套指令 | 支持v-else-if/v-else | 无配套指令,仅单独使用 |
5.3、属性绑定v-bind
v-bind基础语法
在Vue.js中,v-bind 指令用于动态绑定HTML属性到Vue实例的数据。基本语法如下:
<h1 v-bind:属性名="data中的变量"></h1>
v-bind简写形式
Vue提供了v-bind的简写形式,直接使用冒号 : 替代v-bind::
<h1 :属性名="data中的变量"></h1>
示例
clssObj需要用的CSS样式
<style>
.red {
background-color: red;
padding: 10px;
}
.fontWhite {
color: #fff;
font-size: 16px;
}
</style>
html文件
<body>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.2/vue.min.js"></script>
<div id="app">
<h1 v-bind:name="username">v-bind属性绑定</h1>
<h1 :name="username">v-bind的简写</h1>
<h1 :style="styleText">指定style属性样式字符串</h1>
<button :style="styleObj">指定style属性样式对象</button>
<p :class="classObj">指定class属性对象</p>
</div>
<script>
new Vue({
el: "#app",
data: {
username: "jack",
styleText: "background-color:red",
styleObj: {
backgroundColor: "red",
color: "#fff"
},
classObj: {
red: true,
fontWhite: true
}
}
})
</script>
</body>
5.4、列表渲染v-for
基础语法
<li v-for="(value, key) in 数组或对象"></li>
示例
<body>
<!-- <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.2/vue.min.js"></script> -->
<script src="vue2.min.js"></script>
<div id="app">
<!-- 遍历数组 -->
<ul>
<li v-for="(value,key) in arr" :key="value">
{{value}}:{{key}}
</li>
</ul>
<!-- 遍历对象 -->
<ul>
<li v-for="(username,id) in obj" :key="id">
{{username}}:{{id}}
</li>
</ul>
<!-- 遍历对象,解构 -->
<ul>
<li v-for="{username,id} in objArr" :key="id">
{{username}}:{{id}}
</li>
</ul>
<!-- 虽然v-if和v-for同时使用,但是不推荐同时使用 -->
<!-- <p v-for="(value,key) in arr" v-if="arr.length>0">{{value}}:{{key}}</p> -->
</div>
<script>
new Vue({
el: "#app",
data: {
arr: ["西瓜", "香蕉"],
obj: {
id: 1,
username: "张三"
},
objArr: [
{
id: 2,
username: "李四"
},
{
id: 3,
username: "王五"
}
]
}
})
</script>
</body>
需要绑定属性key,绑定key为了提高diff比对的效率,key必须存在,不推荐使用下标作为key(应该严格使用唯一标识id)。
5.4.1、v-for中key的作用(面试题)
在Vue中,v-for指令用于渲染列表,而key属性在v-for中起着至关重要的作用。它的主要作用如下:
-
帮助Vue跟踪每个节点的身份:key是一个特殊的属性,用来为每个列表项提供唯一标识符。Vue使用这个标识来识别每个节点的身份,从而在列表发生变化时(如新增、删除、排序等),能够高效地更新DOM。
-
优化性能:当列表数据发生变更时,Vue会通过key来判断哪些元素可以复用、哪些需要移动或删除。如果没有key,Vue会采用“就地复用”的策略,可能导致不必要的DOM操作或状态错乱。
-
维持组件状态:如果列表项包含有状态的组件(例如
<input>或自定义组件),使用key可以确保组件的状态不会因为列表顺序变化而错乱。 -
支持过渡动画:在使用
<transition-group>对列表进行动画过渡时,key是必需的,它帮助Vue区分哪些元素是新加入的,哪些是即将离开的。 -
避免错误复用:若不使用key,Vue默认会使用索引作为key,当列表顺序改变时,可能会导致元素被错误复用,进而引发状态错乱等问题。
总结来说,key的核心作用是为每个列表项提供一个稳定且唯一的标识,使Vue能够准确识别节点,从而实现高效的DOM更新和状态管理。
5.4.2、v-for和v-if的优先级(面试题)
Vue2 中的优先级
在Vue2中,v-for的优先级高于v-if。这意味着当这两个指令同时作用于同一个元素时,Vue会先执行v-for循环,然后再对每一项执行v-if判断。这种执行顺序会导致性能问题,因为即使某些项不满足v-if的条件,v-for仍然会遍历整个列表。
Vue3 中的优先级
在Vue3中,v-if的优先级高于v-for。这意味着Vue会先执行v-if的判断,只有当条件为真时才会执行v-for循环。这种改变提升了性能,避免了不必要的循环和判断。
注:vue3中可以使用template标签放在外层一起使用
<template v-if="isRender"> <p v-for="item in items" :key="item.id"> {{ item.title }} </p> </template>
为什么不能同时使用?(重点)
虽然在技术上可以将v-if和v-for同时用在一个元素上,但不推荐这样做。
因为这会导致以下问题:
-
性能浪费:即使某些项不满足条件,也会进行不必要的循环和判断。
-
逻辑混乱:可能导致代码难以理解和维护。
vue3针对俩者一起使用会报错。
5.5、事件绑定v-on
基础语法
<button v-on:事件名="methods选项中的处理函数">点击</button>
简写形式(推荐)
<button @事件名="methods选项中的处理函数">点击</button>
事件修饰符
-
stop 阻止事件冒泡
-
prevent 阻止默认行为
-
capture 使用捕获模式
-
self 只有自身才执行事件
-
once 只监听一次
-
passive 修饰符一般用于触摸事件的监听器,可以用来改善移动端设备的滚屏性能。
按键修饰符(键盘事件)
-
enter 回车
-
up 上
-
down 下
-
left 左
-
right 右
-
delete 删除键
-
esc esc键
-
...
示例
css样式
<style>
#box {
background-color: red;
width: 200px;
height: 200px;
}
</style>
html文件
<body>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.2/vue.min.js"></script>
<div id="app">
<button v-on:click="handlerClick">点击</button>
<button @click="handlerClick()">点击简写</button>
<button v-on:click="handlerParamsClick('你好')">传参点击</button>
<p></p>
<!-- 计数器 -->
<button @click="count--">-</button>
{{count}}
<button @click="add()">+</button>
<p></p>
<!-- 事件修饰符 -->
<a href="http://www.baidu.com" @click.prevent="console.log('点击了跳转按钮')">百度地址</a>
<!-- <div @click.capture="console.log('捕获')"> -->
<div @click.self="console.log('div被点击了...')" id="box">
<button @click.stop="console.log('点击了1...')">冒泡</button>
<button @click.stop="console.log('点击了2...')">取消冒泡</button>
<button @click.once="console.log('只点击一次')">只点击一次</button>
<button @click.once.stop.prevent="console.log('事件修饰符可以连用')">连用</button>
</div>
<!-- 按键修饰符 -->
<input type="text" @keyup.enter="console.log('回车触发')">
</div>
<script>
new Vue({
el: "#app",
data: {
msg: "hello world",
count: 0
},
methods: {
handlerClick(arg) {
console.log('点击', this.msg);
},
handlerParamsClick(arg) {
console.log('参数处理', arg);
},
add() {
this.count++;
}
}
})
</script>
</body>
为什么Vue中不能用箭头函数定义methods/钩子函数?
在Vue的methods方法、生命周期钩子(如created/mounted)、computed计算属性、watch侦听器等选项中,绝对不能使用箭头函数,核心原因是箭头函数的this绑定规则与Vue的实例机制冲突:
箭头函数的this特性
箭头函数没有独立的this上下文,它的this是在定义时继承自外层作用域的this,而非调用时动态绑定。简单说,箭头函数的this从一开始就固定了,无法被修改。
Vue的this绑定逻辑
Vue内部会通过bind方法,自动将methods、钩子函数等普通函数的this绑定到当前Vue实例(即vm对象)上。这样开发者才能通过this访问到实例中的data数据、其他methods方法、props属性等。
使用箭头函数的后果
如果用箭头函数定义这些选项,箭头函数的 this 会继承自外层的全局作用域:
-
浏览器环境下,this会指向window对象;
-
Node环境下,this会指向global对象;
这会导致无法通过this访问Vue实例的任何成员,出现undefined报错,比如无法读取this.msg、无法调用this.otherMethod()等。
钩子函数:自动调用。
5.6、双向绑定v-model
v-model是用于数据和视图绑定的指令,主要用于表单元素(绑定的是value值)。
v-model的底层实现:obServed+数据劫持。
它监听了对应的input的change事件|input事件,动态更改了对应的text的值。
相关修饰符
-
lazy 不监听input事件而监听change事件
-
number 转为number类型 (内部调用了Number方法)
-
trim 去空格 (内部调用trim方法)
基础语法
<input type="text" v-model="message">
示例
<body>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.2/vue.min.js"></script>
<div id="app">
<input type="text" v-model="text"> {{text}}
<p></p>
<input type="checkbox" value="西瓜" name="foods" v-model="foods">
<input type="checkbox" value="香蕉" name="foods" v-model="foods">
<input type="checkbox" value="葡萄" name="foods" v-model="foods">
{{foods}}
<p></p>
<input type="checkbox" v-model="value"> {{value}}
<p></p>
<input type="radio" value="男" name="sex" v-model="radioValue"> 男
<input type="radio" value="女" name="sex" v-model="radioValue"> 女
{{radioValue}}
<p></p>
<input type="date" v-model="date">
{{date}}
<p></p>
<select v-model="selectValue">
<option value="">--</option>
<option value="葡萄">葡萄</option>
<option value="香蕉">香蕉</option>
</select>
{{selectValue}}
<p></p>
<input type="checkbox" v-model="toggle" true-value="yes" false-value="no" />
{{toggle}}
<p></p>
<input type="text" v-model.lazy="lazyValue"> {{lazyValue}}
<p></p>
<input type="number" v-model.number="count"> {{count.toFixed(2)}}
<p></p>
<input type="text" v-model.trim="trimValue"> {{trimValue}}
</div>
<script>
new Vue({
el: "#app",
data: {
text: "文本内容",
foods: [],
value: true,
radioValue: "",
date: "",
selectValue: "",
toggle: "",
lazyValue:"",
count:0,
trimValue:""
}
})
</script>
</body>
v-model会忽略任何表单元素上初始的value、checked或selected attribute。它将始终将当前绑定的JavaScript状态视为数据的正确来源。
对于需要使用IME的语言 (中文,日文和韩文等),你会发现v-model不会在IME输入还在拼字阶段时触发更新。如果你的确想在拼字阶段也触发更新,请直接使用自己的input事件监听器和value绑定而不要使用v-model。
如果v-model表达式的初始值不匹配任何一个选择项,<select>元素会渲染成一个 “未选择” 的状态。在iOS上,这将导致用户无法选择第一项,因为iOS在这种情况下不会触发一个change事件。因此,我们建议提供一个空值的禁用选项。
为什么v-model与checked属性不能共用?
核心结论
v-model和checked不能共用的本质是两者对表单元素选中状态的控制逻辑冲突,v-model会完全接管状态管理,导致checked失效,甚至引发状态混乱。
详细解释
两者的底层逻辑不同
checked是HTML原生属性,属于单向赋值:仅在页面初始化时根据checked的值(true/false)设置元素选中状态,后续用户手动操作(如点击复选框)不会同步更新checked属性值,也无法通过修改checked动态改变元素状态。
v-model是Vue的双向绑定语法糖:底层同时做了三个关键操作:
-
初始化时根据绑定的变量值设置元素的checked状态。
-
监听元素的change事件,将用户操作的状态同步到绑定变量。
-
监听绑定变量的变化,实时把变量值同步回元素的选中状态。
共用时的冲突表现
当两者共用时,相当于给元素的选中状态设置了“两个控制源”:
Vue会优先以v-model绑定的变量值为准,直接覆盖checked属性的初始值,导致checked完全失效。
即使手动修改checked属性,v-model的双向绑定机制也会立刻“纠正”元素状态,始终与绑定变量保持一致,最终checked无法起到任何作用。
极端情况下还会出现“变量值与页面显示状态不一致”的混乱(如变量为false但checked="true",页面却显示未选中)。
5.7、其他指令
-
v-once 只渲染一次
-
v-cloak 指定初始渲染阶段的样式
-
v-pre 跳过编译
示例
css代码
<style>
/* 属性选择器 */
[v-cloak] {
display: none;
}
</style>
html代码
<body>
<div id="app" v-cloak>
<p v-once>{{msg}}</p>
<button @click="changeMsg()">更改msg的值</button>{{msg}}
<p v-pre>{{msg}}</p>
</div>
<!-- <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.2/vue.min.js"></script> -->
<script src="vue2.min.js"></script>
<script>
new Vue({
el: "#app",
data: {
msg: 'hello'
},
methods: {
changeMsg() {
this.msg = '新的值'
}
}
})
</script>
</body>
5.8、插槽v-slot(2.6及以后支持)
插槽是顶留的接口,它可以传入对应的内容。v-slot用于指定对应的插槽。
组件的使用
-
定义插槽,slot标签具备name属性,具备name属性的插槽称为具名插槽
-
具备插槽的组件 一定得是双标签调用
-
内部传递得内容就是给插槽得内容
-
默认传递的内容都是传递给匿名插槽的,
v-slot的简写 #插槽名='作用域插槽的相关变量值' -
传递给具名插槽,v-slot来指定插槽,
v-slot:插槽名="作用插槽相关变量 -
作用域(
scope)插槽,扩大组件内属性的作用域,使对应的父组件可以访问对应的组件的内容
注册全局组件,全局组件无需在组件内部注册
组件名,组件的配置项
基础语法
<template v-slot:插槽名="插槽的属性变量"></template>
简写语法
<template #插槽名="插槽的属性变量"></template>
示例
<body>
<div id="app">
<Hello>
<template #default>
<b>传递给匿名插槽的内容</b>
</template>
<template #center>
<b>传递给具名插槽的内容</b>
</template>
<template #foot="scope">
<b>传递给作用域插槽foot的内容{{scope.nickname}}</b>
</template>
</Hello>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.2/vue.min.js"></script>
<script>
Vue.component('Hello', {
data() {
return {
name: "jack"
}
},
template:
`<div>
<h2>插槽组件</h2>
<!-- 匿名插槽 -->
<slot></slot>
<br/>
<!-- 具名插槽 -->
具名插槽的内容:<slot name="center"></slot>
<!-- 作用域插槽 -->
<slot name="foot" :nickname='name'></slot>
</div>`
})
new Vue({
el: "#app",
data: {
}
})
</script>
</body>
5.9、自定义指令
-
el:指令所绑定的元素,可以用来直接操作 DOM。
-
binding:一个对象,包含以下 property:
name:指令名,不包括 v- 前缀。
value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
-
vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
-
oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
全局自定义(必须在对应编译挂载之前)directive
Vue2 全局自定义指令语法
Vue.directive('指令名', {
bind: function (el, binding, vnode) {},
inserted: function (el, binding, vnode) {},
update: function (el, binding, vnode, oldVnode) {},
componentUpdated: function (el, binding, vnode, oldVnode) {},
unbind: function (el, binding, vnode) {}
})
Vue3 全局自定义指令语法
app.directive('指令名', {
beforeMount(el, binding, vnode) {},
mounted(el, binding, vnode) {},
beforeUpdate(el, binding, vnode, prevVnode) {},
updated(el, binding, vnode, prevVnode) {},
beforeUnmount(el, binding, vnode) {},
unmounted(el, binding, vnode) {}
})
简写形式(仅在 bind/mounted 和 update 触发相同操作时使用)
// Vue2
Vue.directive('指令名', function(el, binding) {})
// Vue3
app.directive('指令名', (el, binding) => {})
局部自定义指令语法
export default {
directives: {
指令名: {
// 生命周期钩子(Vue2/Vue3按需选择对应版本)
}
}
}
Vue2的自定义指令
相关钩子
一个指令定义对象可以提供如下几个钩子函数(均为可选):
-
bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
-
inserted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)。
-
update:所在组件的VNode更新时调用,但是可能发生在其子VNode更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新(详细的钩子函数参数见下)。
-
componentUpdated:指令所在组件的VNode及其子VNode全部更新后调用。
-
unbind:只调用一次,指令与元素解绑时调用。
<div id="app">
<input type="text" v-focus>
<h1 v-color="'red'">全局自定义指令</h1>
<h1 v-big>全局自定义指令</h1>
<h1 v-height="100">局部自定义指令</h1>
<h1 v-small>局部自定义指令</h1>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.2/vue.min.js"></script>
<script>
// 全局指令注册
Vue.directive('color', (el, binding, vnode) => {
el.style.color = binding.value
})
Vue.directive('big', (el, binding, vnode) => {
el.style.fontSize = '60px'
})
Vue.directive('focus', {
bind(el, binding, vnode) {
el.focus()
el.value = '聚焦了'
}
})
new Vue({
el: "#app",
data: {},
directives: {
'height': {
inserted(el, binding, vnode) {
el.style.height = binding.value + 'px'
},
},
small(el, binding, vnode) {
el.style.fontSize = '10px'
}
}
})
</script>
Vue3的自定义指令
相关钩子
-
created:在绑定元素的attribute前或事件监听器应用前调用。
-
beforeMount:在元素被插入到DOM前调用。
-
mounted:在绑定元素的父组件及它自己的所有子节点都挂载完成后调用。
-
beforeUpdate:绑定元素的父组件更新前调用。
-
updated:在绑定元素的父组件及它自己的所有子节点都更新后调用。
-
beforeUnmount:绑定元素的父组件卸载前调用。
-
unmounted:绑定元素的父组件卸载后调用。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue3 Custom Directives</title>
</head>
<body>
<div id="app">
{{title}}
<!-- 全局自定义指令 -->
<p v-bold>字体加粗</p>
<p v-italic>字体斜体</p>
<!-- 局部自定义指令 -->
<p v-background="'red'">背景变红</p>
<p v-width="50">宽度为50</p>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.5.2/vue.global.min.js"></script>
<script>
const App = {
data() {
return {
title: 'hello vue3',
}
},
directives: {
background(el, binding, vnode) {
el.style.background = binding.value
},
width: {
mounted(el, binding, vnode) {
el.style.width = binding.value + "px"
}
}
}
}
const app = Vue.createApp(App)
// 全局简写指令(自动绑定到mounted和updated)
app.directive('bold', (el, binding, vnode) => {
el.style.fontWeight = 'bold'
})
// 全局完整生命周期指令
app.directive('italic', {
created(el, binding, vnode) { },
beforeMount(el, binding, vnode) { },
mounted(el, binding, vnode) {
el.style.fontStyle = 'italic'
},
beforeUpdate(el, binding, vnode, prevVnode) { },
updated(el, binding, vnode, prevVnode) { },
beforeUnmount(el, binding, vnode) { },
unmounted(el, binding, vnode) { }
})
app.mount('#app')
</script>
</body>
</html>
1万+

被折叠的 条评论
为什么被折叠?



