- Vue的一个实例对应一个唯一的容器,在HTML中可以设置多个实例。在创建Vue实例之前,可以先设置Vue的一些全局配置,再实例化Vue,关联容器。
- 创建Vue实例使用
new关键字,传递一个配置对象。
<html lang="en">
<head>
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
</head>
<body>
<div id="root">
<p>{{name}}</p>
</div>
</body>
<script type="text/javascript">
/** 先设置全局配置 */
// 阻止Vue在启动时生成生成提示
Vue.config.productionTip = false;
// 创建Vue实例 el的两种写法
// 方式一
new Vue({
el:'#root',
data: {
name:'hello'
},
});
// 方式二
const vm = new Vue({
data: {
name:'hello'
},
});
vm.$mount('#root');
// 创建Vue实例 data的两种写法
// 方式一:对象式
new Vue({
el:'#root',
data: {
name:'hello'
},
});
// 方式二:函数式 使用组件时,data必须使用函数式
const v = new Vue({
data() {
// this,这里的this指向的是Vue实例,不可使用箭头函数,否则this会指向window
return {
name:'hello'
}
},
});
v.$mount('#root');
</script>
</html>
-
Vue.config.productionTip = false;表示阻止Vue在启动时生成生成提示 - 模板语法分为
插值语法({{ }})和指令语法(v-model等)
v-model双向绑定一般用在表单类元素上,单选、多选、输入框等带有value属性的元素。
v-model:value="name"简写v-model="name" - data中的所有属性都出现在Vue实例对象上,vm实例对象上所有的属性以及Vue原型上的所有属性在Vue模板中都能直接使用。
mtehods中的方法、计算属性computed也会添加到vm上
image.png
image.png
Object.defineProperty(object, property, descriptor)
给对象添加属性,以下示例给person对象添加一个age属性,可读可写。
set和get调用时机
- 设置number = 50,执行person.age会先去调用get函数,get函数被调用时返回number的值
- 执行person.age = 100时,在修改age属性的值,set函数会立即被调用,number的值随之改变
let number = 10;
let person = {
name:'渚清与沙白',
sex:'男'
}
/**
* object: person 目标对象
* property: age 属性名
* descriptor: {
* value: 指定一个初始值
* enumerable:是否可以枚举
* writable:是否可编辑
* configurable:是否可删除
* set: age属性值被修改时调用
* get: age属性被读取时调用
* }
*/
Object.defineProperty(person,'age',{
// value:15,// 指定age的值
// enumerable:true,// 是否可枚举
// writable:true,// 是否可编辑
// configurable:true,// 是否可删除
// 当修改age属性时,set函数会被调用
set(value){
console.log('set函数被调用')
number = value;
},
// 当读取age的值时,get函数会被调用
get(){
console.log('get函数被调用')
return number;
}
})
数据代理
通过一个对象代理对另一个对象属性的操作(读/写...)
let obj = {x : 100}
let obj2 = {y: 3};
Object.defineProperty(obj2,'x',{
set(value){
obj.x = value;
},
get(){
return obj.x;
}
})
- Vue中的数据代理
通过vm对象来代理data对象中属性的操作(读/写...)
基本原理:通过Object.defineProperty()把data对象所有属性添加到vm上,为每一个添加到vm上的属性,都指定一个getter/setter。在getter/setter内部去操作(读/写...)data中对应的属性。
image.png
this指向问题
const vm = new Vue({
data() {
// this,这里的this指向的是Vue示例,不可使用箭头函数,否则this会指向 window
return {
name:'hello',
show:false,
}
},
methods: {
showName(){
// 此处的this指向 vm
console.log(this);
},
hideName: ()=>{
// 箭头函数 此处的this指向 window
console.log(this);
}
},
});
vm.$mount('#root');
事件
传参
- 不传参,可不加括号
- 传参,必须加括号
- 传参并使用event,在参数后面 增加
$event占位符即可,传参无先后顺序,但要与mathods中的方法保持一致。
事件修饰符
@click.prevent 阻止默认行为
@click.stop 阻止时间冒泡
@click.once 事件只执行一次
@click.capture 使用事件的捕获阶段
@click.self 只有event.target是当前操作的元素才触发事件
@click.passive 事件的默认行为立即执行,无需等待事件回调执行完毕
@click.native 给子组件添加内置事件,否则在子组件上会被认为是自定义事件
@scroll 滚动条滚动监听
@wheel 鼠标滚轮滚动监听 (会先执行事件回调,回调执行完了才会执行默认行为)可以使用@click.passive立即执行默认行为
- 阻止冒泡并且停止默认事件
@click.stop.prevent修饰符可以连着写
键盘事件
@keydown、@keyup
if(e.keyCode === 13){
// 监听到了回车键事件
}
- 按键别名
@keyup.enter回车键
@keyup.delete删除、退格
@keyup.esc退出
@keyup.space空格
@keydown.tab换行 必须配合keydown使用
@keyup.up上
@keyup.down下
@keyup.left左
@keyup.right右
- vue未提供别名的按键,可以使用按键原始key值去绑定,但是要转为
keybab-case(短横线命名)
@keyup.caps-lock - 系统修饰键
ctrl shift alt meta特殊按键
配合keyup使用时,按下修饰键的同时,再按下其他键,随后释放其他键,事件才会被触发
配合keydown使用时,正常触发事件 - 可以通过键码keyCode去指定具体的按钮,不推荐
@keyup.13 - Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名 , 不推荐
Vue.config.keyCodes.huiche = 13;
@keyup.huiche -
@keyup.ctrl.y按下Ctrl和y键才执行
计算属性computed
- 定义
要用的属性不存在data中,要通过data中已有的属性计算得来 - 原理
底层借助了Object.defineProperty()方法提供的getter和setter。 - get函数执行时机
- 初次读取会执行一次
- 当依赖的数据发生改变时,会再次被调用
- 优势
与methods相比,内部有缓存机制,可以复用, 效率高 - 备注
- 计算属性最终会出现在vm上,可以直接使用
{{ fullName }},错误写法 {{ fullName() }} - 如果计算属性要被修改,必须使用set方法去响应修改,且set中要引起依赖的数据发生改变。修改计算属性的方式:
this.fullName = ‘redColor’直接对计算属性赋值。
注意:这里直接对data属性进行赋值操作并不会引起计算属性中的set函数执行。
// 完整写法
computed:{
fullName:{
get(){
return this.name + ',欢迎您';
},
set(val){
this.name = val;
}
}
}
data() {
return {
name: "A",
};
},
methods: {
modifyNmae() {
this.fullName = "B"; // 修改计算属性的值,才会执行set函数
},
},
// 简写 只读取,不修改
computed:{
fullName(){
return this.name + ',欢迎您'
}
}
- 计算属性传参
// 将参数传递给计算属性
<div>{{ name('张三') }}</div>
computed: {
name() {
// 这里 return 的是一个有形参的函数
return (type) => {
return `姓名:${type}`;
};
},
},
监视属性 watch
可以监视 data中的属性、computed中的属性、props
- 监视属性写法
- new Vue时传入watch
- 通过vm.$watch监视
- 在组件中的配置项添加
watch配置
默认不监视对象内部属性的改变,需要配置deep: true才可以监测内部变化
Vue自身可以监测对象内部值的变化,但Vue提供的watch默认不可以。
data() {
return {
name: "hello",
numbers: {
x: 0,
y: 1,
},
};
},
watch: {
name: {
// name的值发生改变时调用
handler(newVal, oldValue) {
// handler函数名是固定写法
},
immediate: true, // 初始化时,让handler调用一次
},
// 监视对象中某个属性的变化
"number.x": {
handler() {},
},
// 监视多级结构中的所有属性
numbers:{
handler() {},
deep:true,//深度监视
}
},
- watch
简写形式
当配置项中只有handler()时(没有immediate,deep),可以简写。
watch: {
name(newVal,oldVal){ }
},
vm.$watch('name', funcation (newVal, oldVal){ })
vue管理的函数都不能写成箭头函数
watch可以开启异步任务维护数据,但是computed不可以。
因为computed需要return一个返回值,在异步任务seTimeout((){},1000)中return一个值,是将返回值return给了setTimeout,并没有return给computed,此时computed得到的值是undefined,所以无法做异步任务。而watch不一样,它不需要return一个值,可以在异步任务中直接操作数据即可。
watch: {
// ✅ 可以执行异步任务
name(newVal){
setTimeout(()=>{
this.name = 'A';
},1000);
},
},
computed:{
fullNmae(){
// ❌ 不可执行异步任务
setTimeout(()=>{
return this.name + ' B';// 这里的return 将值返回给了settimeout,fullName并没有返回值
},1000);
}
}
动态绑定样式
三种写法:字符串写法、对象写法、数组写法
data() {
return {
mode:'normal',
arr: ['top','center','bottom'],
classObj: {
top: true,
bottom: false,
},
styleObj:{
fontSize: '40px',// fontSize要写成驼峰
}
},
}
<!--class 字符串写法 -->
<p class="basic" :class="mode">hello</p>
<p class="basic" :class="'normal'">hello</p>
<!-- 数组写法 -->
<p class="basic" :class="arr">world</p>
<p class="basic" :class="[ 'top', 'center', 'bottom' ]">world</p>
<!-- 对象写法 -->
<p class="basic" :class="classObj">world</p>
<p class="basic" :class="{ top: true, bottom: false }">world</p>
<!--style 对象写法 -->
<p class="basic" :style="styleObj">world</p>
<p class="basic" :style="{ fontSize: '40px' }">world</p>
<!-- 数组写法 -->
<p class="basic" :style="[ styleObj ]">world</p>
条件编译
v-show的原理是调整css样式display属性
v-if
v-else-if
v-else
<tenplate/>标签不会影响结构,只能配合v-if,不能配合v-show
列表渲染
-
v-for要绑定key属性 - 遍历使用
in、of都可以 - 列表渲染的数据类型支持
数组、对象和字符串 - 遍历指定次数
a of 10
key
对列表进行唯一标识
-
虚拟DOM中key的作用
key是虚拟DOM对象的标识,当数据发生变化时,Vue会根据【新数据】生成【新的虚拟DOM】,
随后Vue进行【新虚拟DOM】与【旧虚拟DOM】的差异比较。 -
对比规则
(1). 旧虚拟DOM中找到了与新虚拟DOM相同的key
①. 若虚拟DOM中内容没变,直接使用之前的真实DOM
②. 若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
(2). 旧虚拟DOM中未找到与新虚拟DOM相同的key
创建新的真实DOM,随后渲染到页面 -
使用index作为key可能会引发的问题
(1). 若对数据进行逆序添加、逆序删除等破坏顺序操作,如arr.unshift ('A')
会让之后的真实DOM产生没有必要的更新,UI没有问题,但是效率低(2). 如果结构追踪还包含输入类的DOM,如
<input />
会产生错误DOM更新,UI数据错乱问题
Vue监测数据变化的原理
Vue.set
Vue.set(target, key, value) | this.$set(target, key, value)
向响应式对象中(data中定义的数据)添加一个属性,并确保这个新 属性 同样是响应式的,且触发视图更新。只能给data对象中的对象添加响应式属性。不能给data这个对象添加属性.注意对象不能是 Vue 实例,或者 Vue 实例的根数据对象。
原理
- vue会监视data中所有层次的数据
- 如何监测对象中的数据
通过setter实现监视,且要在new Vue时就传入要检测的数据(data对象)
(1). 对象中后追加的数据,Vue默认不做响应式处理
(2). 如需给后添加的属性做响应式,请使用下列API
Vue.set(target, key, value)
this.$set(target, key, value) - 如何监测数组中的数据
通过包裹数组更新元素的方法实现,本质就是做了两件事
(1). 调用原生对应的方法对属性进行更新 Array.push等
(2). 重新解析模板,更而更新页面 - 在Vue修改数组中的某个元素一定要用下列方法
(1). 使用这些API:push()pop()shift()unshift()splice()sort()reverse()
(2). Vue.set() 或 vm.$set()。不能使用这两个方法给vm的跟数据对象添加属性。如data对象
双向绑定运用技巧
v-model 双向绑定是一个看作传递 props 和设定自定义事件的语法糖。
v-model是绑定元素中的value属性的值
-
v-model修饰符
v-model.number将输入框的数字转换成Number类型
v-model.lazy失去焦点时收集数据
v-model.trim去除文本前后空格 - 收集表单数据v-model的使用
-
<input type="text"/>v-model收集的是value的值,用户输入的就是value值 -
<input type="radio"/>v-model收集的是value值,且要给标签配置value属性 -
<input type="checkbox"/>v-model收集值有以下两种情况
(1).没有配置input的value属性,则收集的就是checked值,true or false
(2).配置input的value属性,如v-model的初始值是非数组,收集的是checked值;初始值是数组,收集的是value组成的数组
-
-
高级用法
1. 自定义组件实现双向绑定的能力
export default {
model: {
prop: 'value',
event: 'input',// 双向绑定的事件 input
},
props:
value: [String, Number],// v-model支持多类型数据
},
emits: ['input'],// 定义事件 input
data() {
return { };
},
methods: {
input(e){
this.$emit('input',e.target.value);// 输入值后,通过事件改变
}
},
};
2. v-model绑定不同的数据
实现方式:通过计算属性来实现
<input v-model="rate"/> // 绑定计算属性 rate
export default{
data:{
return {
type:0,
getPercent: '',
ratePercent: '',
};
},
computed:{
rate: { // 计算属性rate
get() {// 获取值 根据条件判断
if (!this.type) return this.getPercent;
if (this.type) return this.ratePercent;
},
set(value) { // 设置值,根据条件
if (!this.type) this.getPercent = value;
if (this.type) this.ratePercent = value;
},
},
}
}
3. v-model双向绑定多个值
可参考:https://www.cnblogs.com/Im-Victor/p/16121210.html
<template>
<view>
<price-range
label="价格范围"
:disabled="isEdit"
:start.sync="form.startPrice"
:end.sync="form.endPrice" />
</view>
</template>
export default {
name: 'PriceRange',
props: {
label: String,
start: [String, Number],
end: [String, Number],
disabled: {
type: Boolean,
default: false,
},
},
emits: ['blur'],
computed: {
startValue: {
get() {
return this.start;
},
set(val) {
this.$emit('update:start', val);
},
},
endValue: {
get() {
return this.end;
},
set(val) {
this.$emit('update:end', val);
},
},
},
watch: {
startValue(newVal) {
if (!newVal) return;
const text = newVal.replace(/[^0-9]{0,1}(\d*(?:\.\d{0,2})?).*$/, '$1');
this.$nextTick(() => {
this.$emit('update:start', text);
});
},
endValue(newVal) {
if (!newVal) return;
const text = newVal.replace(/[^0-9]{0,1}(\d*(?:\.\d{0,2})?).*$/, '$1');
this.$nextTick(() => {
this.$emit('update:end', text);
});
},
},
data() {
return {};
},
};
</script>
过滤器
可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值 和 v-bind 表达式
-
语法
- 注册过滤器:
Vue.filter(name, callback)或new Vue(filters:{}) - 使用过滤器:
{{ xxx | 过滤器名 }}或v-bind:属性 = “xxx | 过滤器名”
注意使用格式:|分隔
- 注册过滤器:
-
使用方法
(1)插值语法
<p> {{ time | timeFormatter }} </p>
filters:{
// 定义了形参
timeFormatter(value){
return 'hello';
}
}
<p>{{time | timeFormatter}}</p> 含义:先读取time,然后将time作为参数传递给timeFormatter函数;拿到timeFormatter的返回值替换插值语法中的内容。
(2)v-bind中使用过滤器
<h2 :x="time | slice">渚清与沙白</h2>
- 过滤器传参
默认将time作为timeFormatter函数的第一个参数传递
// 看似没传参数,实则会传递time参数
<p>{{ time | timeFormatter }}</p>
// 这里第一个参数会自动处理为time,第二个参数才是'YYYY/MM/DD'
<p>{{ time | timeFormatter('YYYY/MM/DD') }}
filters:{
// 定义形参参数仍是两个
timeFormatter(value, format = 'YYYY-MM-D'){
return 'hello';
}
}
- 过滤器串连
先将time传递给timeFormatter,再将timeFormatter的返回值继续往下传递给slice函数。
<p> {{ time | timeFormatter('YYYY/MM/DD') | slice }} </p>
filters:{
timeFormatter(value, format = 'YYYY-MM-D') {
return 'hello';
},
slice(value) {
return value.slice(0,4);
}
}
- 局部过滤器注册
在组件中配置的过滤器就是局部过滤器 - 全局过滤器注册
Vue.filter
指令
v-text:向节点渲染文本内容。与插值语法的区别是会替换节点中的内容,插值语法则不会。不支持结构解析,要显示html标签文本内容,可以使用该指令。
v-html:向节点渲染包含html结构的内容。与插值语法的区别是会替换节点中的内容,插值语法则不会。
v-html存在严重的安全问题
在网站上动态渲染html是非常危险的,容易导致XSS攻击;一定要在可信的内容上使用v-html,不要用在内容提交上。
v-cloak:是一个特殊属性,Vue实例创建完毕开始接管容器后,会删除掉v-cloak属性。使用css配合使用,可以解决网速慢的时候页面展示插值语法的问题。如页面展示{{ name }}的问题。
// 选中带有v-cloak属性的所有标签
[v-cloak] {
display: none;
}
<div v-cloak>
{{ message }}
</div>
v-once:初次渲染之后,就视为静态内容了,之后的数据改变不会引起该节点的更新。
v-pre:让Vue跳过该指令所在节点的编译过程,没有使用插值语法和其他指令的节点加上该指令可让vue不再去解析,可以加快编译。
自定义指令:取名不需要加v-,在使用时需要加v-。
自定义指令
- 自定义的三个钩子函数
bind(),insert(),update()。 - 钩子函数调用时机
bind():指令和元素成功绑定时调用
insert():指令所在元素被插入页面时调用
update():指令所在模板被重新解析时调用 - 简写形式
因为bind(),update()这两个函数处理逻辑差不多一致,于是提供了简写形式,将二者合并成一个函数。 - 自定义指令定义
directives、Vue.directive()
- 全局指令
Vue.directive(key,value)
参数key是指令名,指令名存在多个单词,需要使用短横线连接
参数value是回调函数或者配置对象
#对象式
Vue.directive('fbind',{
// 指令和元素成功绑定时调用bind函数
bind(el,binding){
el.value = binding.value;
},
// 指令所在元素被插入页面时调用
insert(el,binding){
el.focus(); // 输入框获取焦点
},
// 指令所在模板被重新解析时调用
update(el,binding){
el.value = binding.value;
}
});
#函数式
Vue.directive('big',function(el,binding){
console.log(this);// this指向window
el.innerHTML = binding.value * 10;
});
- 局部指令
directives:{bind(),insert(),update()}
directives:{
// 回调函数式 简写形式,囊括了bind()和update()函数。
// 因为这两个函数处理逻辑差不多一致,于是提供了简写形式。
// 调用时机:指令与元素成功绑定时会被调用;指令所在模板被重新解析时也会被调用
big(el,binding){
console.log(this);// this指向window
el.innerHTML = binding.value * 10;
},
// 配置对象式
fbind:{
// 指令和元素成功绑定时调用bind函数
bind(el,binding){
el.value = binding.value;
},
// 指令所在元素被插入页面时调用
insert(el,binding){
el.focus(); // 输入框获取焦点
},
// 指令所在模板被重新解析时调用
update(el,binding){
el.value = binding.value;
}
},
// 指令名多个单词问题
'big-number'(el,binding){
el.value = binding.value;
}
}
- this指向
三个钩子函数中的this指向的是window
生命周期
created:指数据监测、数据代理创建完毕
mounted:Vue完成模板解析并把初始的真实DOM放入页面(挂载完毕)后调用
绑定自定义化事件、订阅消息、请求网络、开启定时器
beforeDestory:销毁Vue实例之前时调用
解除消息订阅、关闭定时器、解绑自定义事件;此阶段可以访问vue实例的数据、可以调用vue实例的方法,但是不会触发DOM更新
lifecycle.png
VueDevTools扩展图标高亮显示,但是控制台没有Vue选项卡(Open DevTools and look for the Vue panel),无法进入调试工具。可以在main.js加入Vue.config.devtools = true。最后刷新浏览器或者重启。











网友评论