Vue.js基础学习
Vue基础学习
📚 Vue 学习目录
🚀 Vue.js基础学习 - 📝 Vue.js进阶 - 🔦 webpack学习
📦 Vue-CLI学习 - 📌 Vue-router学习 - 🔮 Vuex学习 - 🎀 Nuxt.js 学习
什么是Vue
Vue是一套用于构建用户界面的渐进式JavaScript框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库
只关注视图层
,方便与第三方库或既有项目整合。
最简单的一个Vue
1 |
|
结果:
1 | Hello World |
Vue实例,每一个应用都是通过Vue这个构造函数创建根实例(root instance)启动New Vue(选项对象)。需要传入选项对象,对象包含挂在元素,数据,模板、方法等。
- el:挂载元素选择器 — String|HtmlElement
- data:代理数据 — Object|Function
- methods:定义方法 — Object
- template:模板、它会替换
<div id="app"></div>
里面的内容
Vue代理data数据,每个vue实例都会代理其data对象里所有的属性,这些被代理的属性是响应的。新添加的属性不具备响应功能,改变后不会更新视图。
Vue实例自身属性和方法,暴露自身的属性和方法,以"$"
开头的,例如:$el、$data ...
解释:我们通过引入vue.js文件、创建Vue对象绑定id
为app
的div、在data
写入msg对象、值为Hello world
,最后在div中通过{{}}(双大括号)绑定了data中msg的值。在控制台中通过 vue.msg = "Hello"
可以动态修改msg的内容。
vue-cli的基本使用
暂时不用 后面通过Vue-cli创建时再使用
安装Vue-cli
1
npm install -g @vue/cli
等待安装完成
- 卸载
1
npm uninstall -g @vue/cli
验证vue版本
1
2
3
4vue -V 或者 vue --version
ps:
-V: 大写字母V创建Vue项目
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17vue create [项目名]
ps:
项目名中不要包含大写字母
可加参数:
-p, --preset <presetName> 忽略提示符并使用已保存的或远程的预设选项
-d, --default 忽略提示符并使用默认预设选项
-i, --inlinePreset <json> 忽略提示符并使用内联的 JSON 字符串预设选项
-m, --packageManager <command> 在安装依赖时使用指定的 npm 客户端
-r, --registry <url> 在安装依赖时使用指定的 npm registry
-g, --git [message] 强制 / 跳过 git 初始化,并可选的指定初始化提交信息
-n, --no-git 跳过 git 初始化
-f, --force 覆写目标目录可能存在的配置
-c, --clone 使用 git clone 获取远程预设选项
-x, --proxy 使用指定的代理创建项目
-b, --bare 创建项目时省略默认组件中的新手指导信息
-h, --help 输出使用帮助信息初学者配置:
Vue CLI v4.3.1
? Please pick a preset:Manually select features
? Check the features needed for your project:Babel, Router, CSS Pre-processors
? Use history mode for router? (Requires proper server setup for index fallback in production)Yes
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default):Less
? Where do you prefer placing config for Babel, ESLint, etc.?In dedicated config files
? Save this as a preset for future projects?No
运行
1
npm run serve
工程目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19├── README.md
├── index.html
├── src
│ ├── App.vue
│ ├── assets
│ │ ├── img
│ │ └── logo.png
│ ├── components
│ │ └──Helloworld.vue
│ ├── views
│ │ └── Home.vue
│ ├── main.js
│ ├── router // 路由配置文件
│ │ └── router.js
│ └── store
│ └──store.js
└── babel.config.js
└── package.json
└── package-lock.json- public存放静态文件
- public/index.html生成项目的入口文件,webpack打包的js,css也会自动注入到该页面中
- src存放各种vue文件的地方
- src/assets用于存放各种静态文件,如图片,css
- src/compnents用于存放我们的公共组件
- src/views用于存放我们写好的各种页面
- src/App.vue主vue组件 引入其他组件,app.vue是项目的主组件,所有页面都是在app.vue下切换的
- src/main.js入口文件,作用是初始化vue实例,也可以在此文件中引用组件库或者全局变量
- src/router.js路由文件,是为各个页面的地址路径
- src/store.js状态文件
- package.json模块基本信息,项目开发所需要模块,版本,项目名称
基本指令
mustache
语法 {{}}通过双大括号 {{}} 绑定data里面的值:{{}} 里面的值为data里面的数据、也可以是表达式
1
2
3{{ msg }}
{{ msg + " : " + type }}v-once
这个指令不需要任何表达式
,它的作用就是定义它的元素或组件只会渲染一次,包括元素或者组件的所有字节点。首次渲染后,不再随着数据的改变而重新渲染。也就是说使用v-once,那么该块都将被视为静态内容。1
<h2 v-once >{{ message }}</h2>
v-html
会把传入的数据解析成html代码1
2
3
4
5
6
7
8
9
10<div id="app">
<h2 v-html="url"></h2>
</div>
const app = new Vue({
el : '#app',
data : {
url : '<a href="http://www.baidu.com"> 百度一下 <a/>'
}
})v-text
用于渲染普通文本 (最好不用这个)、因为会覆盖标签里的内容1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<div id="app">
<h2>{{msg}} + "!"</h2>
<h2 v-text="msg">哈哈哈</h2>
</div>
const app = new Vue({
el : '#app',
data : {
msg: "Hello world"
}
})
渲染结果:
Hello world!
Hello worldv-pre
可以理解为不渲染标签里的内容1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<div id="app">
<h2 v-pre>{{msg}}</h2>
</div>
const app = new Vue({
el : '#app',
data : {
msg: "Hello world"
}
})
渲染结果:
{{ msg }}v-cloak
会在 Vue 实例编译结束时,从绑定的 HTML 元素上被移除。指令是解决屏幕闪动的好方法、但在大型、工程化的项目不需要使用 (不常用)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17html:
<div id="app" v-cloak>
{{msg}}
</div>
css:
[v-cloak]{
display: none;
}
javascript:
const app = new Vue({
el : '#app',
data : {
msg: "Hello world"
}
})
数据绑定 v-bind
v-bind是
用于绑定数据和元素属性的
:v-bind:[属性名]="data中的键名"
、属性名可以为标签属性
或自定义属性
,简写为 :xxx
html属性不能使用 {{}} (双大括号)形式绑定,只能使用
v-bind指令
基本语法
v-bind
语法通过 v-bind 绑定数据
v-bind:[属性]="data中的键名"
1
2
3<div v-bind:title="title" v-bind:type="type">我是第一个div</div>
<div v-bind:title="title1 + ' ' title2" v-bind:type="type">我是第二个div</div>可以简写成
:[属性]
1
<div :title="title" :type="type">我是一个简写的div</div>
也可以写函数
1
2
3
4
5
6
7
8
9
10
11
12
13<div id="app">
<p v-bind:title="getTitle()"通过函数获取title</p>
</div>
var vm = new Vue({
el: '#app',
data: {
getTitle: function () {
return 'title1 title2';
}
}
});动态绑定
v-bind:[data中的键名]="data中的键名"
1
<div v-bind:[attrName]="title">我是用于动态绑定</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
33
34
35
36<template>
<div>
<!--template里面只能有一个子元素、也就是这里的直接div-->
<h1>数据绑定:v-bind</h1>
<!-- {{ }} 里面的值为data里面的数据、也可以是表达式-->
<p>{{ msg }}</p>
<p>{{ msg + " : " + type }}</p>
<!-- 通过v-bind 绑定数据 v-bind:[属性]="data中的键名" -->
<div v-bind:title="title" v-bind:type="type">我是一个div</div>
<!-- 可以简写成 :[属性] -->
<div :title="title" :type="type">我是一个简写的div</div>
<!--动态绑定 v-bind:[data中的键名]="data中的键名" -->
<div v-bind:[attrName]="title">我是用于动态绑定</div>
</div>
</template>
<script>
export default {
name: "Study01",
data() {
return {
msg: "这里是msg的内容",
type: "这里是type的内容",
title: "这里是title的内容",
attrName: "title"
}
},
//钩子函数:mounted是挂载是触发的函数
mounted() {
setTimeout(()=>{
//通过这个动态修改值
this.msg = "通过this.[data中的键名]可以动态修改内容"
},3000)
}
}
</script>渲染结果(3秒后的):
1
2
3
4
5
6
7
8<div>
<h1>基本语法</h1>
<p>通过this.[data中的键名]可以动态修改内容</p>
<p>通过this.[data中的键名]可以动态修改内容 : 这里是type的内容</p>
<div title="这里是title的内容" type="这里是type的内容">我是一个div</div>
<div title="这里是title的内容" type="这里是type的内容">我是一个简写的div</div>
<div title="这里是title的内容">我是用于动态绑定</div>
</div>
Vue生命周期
生命周期 | 是否获取dom节点 | 是否可以获取data | 是否获取methods |
---|---|---|---|
beforeCreate | 否 | 否 | 否 |
created | 否 | 是 | 是 |
beforeMount | 否 | 是 | 是 |
mounted | 是 | 是 | 是 |
Class 与 Style 绑定
绑定Class
绑定一个class值
1
2
3
4<div :class="ClassA">我的class绑定了一个</div>
<div class="title" :class="ClassA">我的class绑定了两个</div>
结果: class="title ClassA" 会合并数组法
绑定多个class值1
<div :class="[ClassA,ClassB]">我的class绑定了多个</div>
对象法
绑定多个class值1
<div :class="ClassObj">我的class通过对象绑定了多个</div>
对象方式{ xxx:boolean }
绑定的是键名、值为true时显示、反之不显示、一定要注意显示的是键名
1
2<div :class="{CA:true,CB:true}">我的class通过对象绑定了多个</div>
<div class="{CA:isA,CB:isB}">我的class通过对象绑定了多个</div>data
1
2
3
4
5
6
7
8
9
10
11
12
13
14data(){
return{
//绑定Class
ClassA : "ClassA",
ClassB : "ClassB",
ClassObj:{
//对象法: 绑定的是键名、值为true时显示、反之不显示、一定要注意显示的是键名
CA:true,
CB:false
},
isA:true,
isB:false
}
}
绑定Style
基本语法
:style="{ 属性名(可以使用驼峰命名或者-):'属性值', 属性名(可以使用驼峰命名或者-):'属性值' }"
1
<div :style="{fontSize:'26px',color:'red'}">我通过Style绑定多个CSS样式</div>
通过对象法绑定
1
2
3
4
5
6
7<div :style="StyleObj">我的style通过对象绑定了多个</div>
//绑定Style
StyleObj:{
fontSize:'15px',
color:'blue'
}通过数组法绑定
1
2
3
4
5
6<div :style="[StyleObj]">我的style通过对象绑定了多个</div>
//绑定Style
StyleObj:{
color:'blue'
}
示例
查看代码
1 | <template> |
渲染结果:
1 | <div> |
条件渲染
v-if
基本语法
v-if="data中的键名"
v-if中为true将会显示元素、false会删除元素v-else-if="data中的键名"
v–else-if中为true将会显示元素、false会删除元素v-else
都不符合将会显示1
2
3<div v-if="isShow">isShow为true我将会显示</div>
<div v-else-if="isShow2">isShow为false,isShow2为true我将会显示</div>
<div v-else>都为false我将会显示</div>小问题:实现动态切换标签 input复用问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17<div id="app">
<span v-if="isUser">
<label for="username">用户账户</label>
<input type="text" id="username" placeholder="用户账户">
</span>
<span v-else="isUser">
<label for="email">用户邮箱</label>
<input type="text" id="email" placeholder="用户邮箱">
</span>
<button @click="isUser=!isUser">切换类型</button>
</div>
const app = new Vue({
el:'#app',
data:{
isUser:true
}当我们在input中输入了内容后点击按钮切换类型、发现input中的数据并没有清空:Vue在进行DOM复用的时候,处于性能考虑,
会尽可能的复用已经存在的元素
,而不是重新创建
。在未使用key
的时候,在虚拟DOM上会在切换类型的时候,将第一个input直接保留放在切换后的input上,由于没有key标识,里面的内容依然保留。所以我们需要给input添加一个key(唯一值)属性可以
1
2
3
4
5
6
7
8
9
10
11<div id="app">
<span v-if="isUser">
<label for="username">用户账户</label>
<input type="text" id="username" placeholder="用户账户" key="username">
</span>
<span v-else="isUser">
<label for="email">用户邮箱</label>
<input type="text" id="email" placeholder="用户邮箱" key="email">
</span>
<button @click="isUser=!isUser">切换类型</button>
</div>
v-show
基本语法
v-show="布尔值"
v-show值为true将会显示标签、false将会添加style=”display: none;” 不会删除元素
1
<div v-show="isShow">isShow为true我将会显示、为false将会隐藏</div
问题:通过外层包裹div显示多个div会多渲染一个
<div></div>
1
2
3
4
5
6
7
8
9
10<div v-show="isShow3">
<div>我是内容1</div>
<div>我是内容2</div>
</div>
渲染结果为
<div>
<div>我是内容1</div>
<div>我是内容2</div>
</div>解决:通过template包裹的不会显示
另一个问题:isShow4为假的时候同样会被显示,原因:在Vue单文件组件的template标签上使用v-if不生效的原因,简单解释一下就是单文件Vue只能包含一个template、所以最好用于v-for。
1
2
3
4<template v-show="isShow4">
<div>我是内容1</div>
<div>我是内容2</div>
</template>示例
查看代码
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<template>
<div>
<h1>v-if添加判断</h1>
<!-- v-if中添加为true将会显示元素、false会删除元素 -->
<div v-if="isShow">isShow为true我将会显示</div>
<div v-else-if="isShow2">isShow为false,isShow2为true我将会显示</div>
<!-- 以上添加不符合将显示 -->
<div v-else>都为false我将会显示</div>
<h1>v-show</h1>
<!-- v-show值为true将会显示标签、false将会添加style="display: none;" 不会删除元素 -->
<!-- 问题:通过外层包裹div显示多个div会多渲染一个<div></div>-->
<div v-show="isShow3">
<div>我是内容1</div>
<div>我是内容2</div>
</div>
<p>-------------------------------------</p>
<!-- 解决:通过template包裹的不会显示-->
<!-- 另一个问题:isShow4为假的时候同样会被显示,原因:https://blog.csdn.net/HermitSun/article/details/105189022 -->
<template v-show="isShow4">
<div>我是内容1</div>
<div>我是内容2</div>
</template>
</div>
</template>
<script>
export default {
name: "Study02",
data() {
return {
isShow: true,
isShow2: false,
isShow3: false,
isShow4: true
}
},
mounted() {
setTimeout(() => {
//2秒后将isShow设为false
this.isShow = false
this.isShow2 = true
}, 2000);
setTimeout(() => {
//4秒后将isShow2设为false
this.isShow2 = false
}, 4000);
}
}
</script>渲染结果(4秒后):
1
2
3
4
5
6
7
8
9
10
11
12<div>
<h1>v-if添加判断</h1>
<div>都为false我将会显示</div>
<h1>v-show</h1>
<div style="display: none;">
<div>我是内容1</div>
<div>我是内容2</div>
</div>
<p>-------------------------------------</p>
<div>我是内容1</div>
<div>我是内容2</div>
</div>
v-for
基本语法
1个参数时:
[变量名、随便取] in [data中的可遍历数据键名]
2个参数时:
([变量名],[索引名]) in [data中的可遍历数据键名]
3个参数时:
([变量名],[键名],[索引名]) in [data中的可遍历数据键名]
注意:Vue建议添加 key , key 代表唯一、更好渲染DOM
1
2
3
4
5
6
7
8
9
10
11<div v-for="array in arrays">{{array}}</div>
<div v-for="(array,index) in arrays" :key="index">{{index}} - {{array}}</div>
<div v-for="(array,key,index) in arrays" :key="index">{{index}} - {{key}} - {{array}}</div>
data() {
return {
arrays: [1, 2, 3, 4, 5]
}
}数组中那些方法是响应式的
方法:
push() pop() shift() unshift() splice() sort() reverse() ...
不是响应式的:通过数组索引之间修改数据、通过这个修改页面中的数据不会更新
1
2
3
4
5methods:{
updateArray(){
this.array[0] = 18;
}
}遍历对象
对象也可以被遍历 由于:key值为index会与上面相同、所以绑定key
in 也可以用 of 进行替换
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<div v-for="(obj,key,index) in objs" :key="key">{{index}} - {{key}} - {{obj}}</div>
<ul :style="{textAlign:'left'}">
<li v-for="person of people">{{person.name}} - {{person.sex}} - {{person.age}}</li>
</ul>
data() {
return {
objs: {
name: "zykj",
sex: "男",
age: 18
},
people:[
{
name: "zykj",
sex: "男",
age: 18
},
{
name: "skx",
sex: "男",
age: 16
},
{
name: "y",
sex: "女",
age: 19
}]
}
}为什么要绑定
key
参考资料: VUE中演示v-for为什么要加key
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<div>
<input type="text" v-model="name">
<button @click="add">添加</button>
</div>
<ul>
<li v-for="(item, i) in list">
<input type="checkbox"> {{item.name}}
</li>
</ul>
data: {
name: '',
newId: 3,
list: [
{ id: 1, name: '李斯' },
{ id: 2, name: '吕不韦' },
{ id: 3, name: '嬴政' }
]
},
methods: {
add() {
//注意这里是unshift
this.list.unshift({ id: ++this.newId, name: this.name });
this.name = '';
}
}当选中吕不为时,添加楠楠后选中的确是李斯,并不是我们想要的结果,我们想要的是当添加楠楠后,选中的是吕不为、此时我们需要绑定key
可以简单的这样理解:加了key(一定要具有唯一性)、id的checkbox跟内容进行了一个关联。是我们想达到的效果
原理
:示例
查看代码
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<template>
<div>
<h1>v-for遍历</h1>
<!-- [变量名、随便取] in [data中的可遍历数据键名] -->
<div v-for="array in arrays">{{array}}</div>
<!-- 2个参数时:([变量名],[索引名]) in [data中的可遍历数据键名] -->
<!--Vue建议添加key,key代表唯一、更好渲染DOM-->
<div v-for="(array,index) in arrays" :key="index">{{index}} - {{array}}</div>
<!-- 3个参数时:([变量名],[键名],[索引名]) in [data中的可遍历数据键名] -->
<div v-for="(array,key,index) in arrays" :key="index">{{index}} - {{key}} - {{array}}</div>
<!--对象也可以被遍历 由于:key值为index会与上面相同、所以绑定key-->
<div v-for="(obj,key,index) in objs" :key="key">{{index}} - {{key}} - {{obj}}</div>
<ul :style="{textAlign:'left'}">
<!-- in 也可以用 of 进行替换 -->
<li v-for="person of people">{{person.name}} - {{person.sex}} - {{person.age}}</li>
</ul>
</div>
</template>
<script>
export default {
name: "Study04",
data() {
return {
arrays: [1, 2, 3, 4, 5],
objs: {
name: "zykj",
sex: "男",
age: 18
},
people:[
{
name: "zykj",
sex: "男",
age: 18
},
{
name: "skx",
sex: "男",
age: 16
},
{
name: "y",
sex: "女",
age: 19
}]
}
}
}
</script>渲染结果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21<div>
<h1>v-for遍历</h1>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>0 - 1</div>
<div>1 - 2</div>
<div>2 - 3</div>
<div>3 - 4</div>
<div>4 - 5</div>
<div>0 - name - zykj</div>
<div>1 - sex - 男</div>
<div>2 - age - 18</div>
<ul style="text-align: left;">
<li>zykj - 男 - 18</li>
<li>skx - 男 - 16</li>
<li>y - 女 - 19</li>
</ul>
</div>
事件监听
v-on
基本语法
v-on:xxx="函数名\表达式"
或者简写@xxx="函数名\表达式"
如:@click="xxx"、@sumbit="xxx"、@input="xxx"(表单输入事件)
在
methods
中写对象的函数方法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<div>当前number:{{number}}</div>
<button v-on:click="add">点我number加一哟</button>
<button @click="reduce">点我number减一哟</button>
<!-- $event为事件对象、当第一个参数为自定义参数时、想获得事件对象可以添加第二参数$event-->
<button @click="reduce(2,$event)">点我number减2哟</button>
methods: {
add() {
this.number++;
},
reduce(val,event) {
//当有两个参数时
if (typeof val == 'number') {
this.number -= val;
//默认有一个事件 MouseEvent
console.log(event);
}
// if(typeof val == 'object'){
//只有一个参数时
else {
this.number--;
console.log(val);
}
}
}注意点:
当函数没有参数时、可以简写成
@click="getName"
, 当然@click="getName()"
也是可以的函数参数:
无传入参数时:默认有一个
event
事件对象1
2
3
4
5
6<button v-on:click="add">点我number加一哟</button>
add(event) {
console.log(event);
this.number++;
}有参数传入时、又想手动传入事件对象、可以传入
$event
1
2
3
4
5
6<button v-on:click="add(2,$event)">点我number加n哟</button>
add(num,event) {
this.number -= num;
console.log(event);
}
$set
与$delete
当我们想动态添加属性和删除数据时、使用
$set
或者$delete
- 不能直接通过 this.xxx[0] = { … } 添加
- 可以使用
$set(target, key, value)
添加 (target可以是对象或数组[那么对应的key就是索引],key 可以是字符串或数字,可以是任何类型) - js 方法
数组名.splice(起始位置,删除个数,添加元素)
删除添加 - 可以使用
$delete(target, key)
添加,target: 可以是对象[那么对应的key就是属性名]或数组,key : 可以是字符串或数字
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<ul :style="{textAlign:'left'}">
<li v-for="person of people" :key="people.id">{{person.name}} - {{person.sex}} -{{person.age}}</li>
</ul>
<button @click="AddPerson">添加一个人</button>
<button @click="RemovePerson">删除一个人</button>
<button @click="UpdatePerson">更新一个人</button>
methods: {
AddPerson() {
//push()向数组的末尾添加一个或更多元素,并返回新的长度。 头部添加unshift
this.people.push({
create: Date.now(),
name: "zykj",
sex: "男",
age: 18
})
},
RemovePerson() {
//pop()删除并返回数组的最后一个元素。头部删除shift
this.people.pop();
},
UpdatePerson() {
//Vue 不允许在已经创建的实例上动态添加新的根级响应式属性
// this.people[0] = {
// create: Date.now() ,
// name: "zykj",
// sex: "男",
// age: 18
// } // 这是错误的
//如果我们需要在运行过程中实现属性的添加,set 方法
//参数:(target, key, value) (target可以是对象或数组,可以是字符串或数字,可以是任何类型)
//这里的0代表索引
// this.$set(this.people,0,{
// create: Date.now() ,
// name: "我修改了数据",
// sex: "女",
// age: 15
// })
//或者原生的js方法:就是通过splice删除一个元素,并且添加一个元素
this.people.splice(0, 1, {
create: Date.now(),
name: "我修改了数据",
sex: "女",
age: 15
})
}
}
set 与 delete
Vue 不允许在已经创建的实例上动态添加新的根级响应式属性。
Vue 不能检测到对象属性的添加或删除,最好的方式就是在初始化实例前声明根级响应式属性,哪怕只是一个空值。
如果我们需要在运行过程中实现属性的添加或删除,则可以使用全局 Vue,Vue.set 和 Vue.delete 方法。
Vue.set
Vue.set 方法用于设置对象的属性,它可以解决 Vue 无法检测添加属性的限制,语法格式如下:
1
Vue.set( target, key, value )
参数说明:
- target: 可以是对象或数组
- key : 可以是字符串或数字
- value: 可以是任何类型
Vue.delete
Vue.delete 用于删除动态添加的属性 语法格式如下:
1
Vue.delete( target, key )
参数说明:
- target: 可以是对象或数组
- key : 可以是字符串或数字
示例
查看代码
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149<template>
<div>
<h1>事件监听v-on</h1>
<h2>操作数组</h2>
<div>当前number:{{number}}</div>
<!-- 通过v-on绑定一个点击事件add、在methods上写add方法 -->
<button v-on:click="add">点我number加一哟</button>
<!-- v-on也可以简写成@ -->
<button @click="reduce">点我number减一哟</button>
<!-- $event为事件对象、当第一个参数为自定义参数时、想获得事件对象可以添加第二参数$event-->
<button @click="reduce(2,$event)">点我number减2哟</button>
<div v-if="isShow">我是v-if</div>
<div v-else>我是v-else</div>
<button @click="toggle">切换isShow的值</button>
<ul :style="{textAlign:'left'}">
<li v-for="person of people" :key="people.id">{{person.name}} - {{person.sex}} - {{person.age}}</li>
</ul>
<button @click="AddPerson">添加一个人</button>
<button @click="RemovePerson">删除一个人</button>
<button @click="UpdatePerson">更新一个人</button>
<p>----------------------------------------------------</p>
<h2>操作对象</h2>
<ul>
<li v-for="(obj,key,index) in objs">{{ index }} - {{key}} - {{obj}}</li>
</ul>
<button @click="AddAttr">添加属性</button>
<button @click="DeleteAttr">删除属性</button>
<button @click="UpdateAttr">修改属性</button>
</div>
</template>
<script>
export default {
name: "Study05",
data() {
return {
number: 1,
isShow: true,
people: [
{
create: 1,
name: "zykj",
sex: "男",
age: 18
},
{
create: 2,
name: "skx",
sex: "男",
age: 16
},
{
create: 3,
name: "y",
sex: "女",
age: 19
}
],
objs: {
name: "zykj",
sex: "男",
age: 20
},
}
},
methods: {
add() {
this.number++;
},
//默认有一个事件 MouseEvent
//reduce(event) {
reduce(val, event) {
//当有两个参数时
if (typeof val == 'number') {
this.number -= val;
console.log(event);
}
// if(typeof val == 'object'){
//只有一个参数时
else {
this.number--;
console.log(val);
}
},
toggle() {
this.isShow = this.isShow ? false : true;
},
AddPerson() {
//push()向数组的末尾添加一个或更多元素,并返回新的长度。 头部添加unshift
this.people.push({
create: Date.now(),
name: "zykj",
sex: "男",
age: 18
})
},
RemovePerson() {
//pop()删除并返回数组的最后一个元素。头部删除shift
this.people.pop();
},
UpdatePerson() {
//Vue 不允许在已经创建的实例上动态添加新的根级响应式属性
// this.people[0] = {
// create: Date.now() ,
// name: "zykj",
// sex: "男",
// age: 18
// }
//如果我们需要在运行过程中实现属性的添加,set 方法
//参数:(target, key, value) (target可以是对象或数组,可以是字符串或数字,可以是任何类型)
//这里的0代表索引
// this.$set(this.people,0,{
// create: Date.now() ,
// name: "我修改了数据",
// sex: "女",
// age: 15
// })
//或者原生的js方法:就是通过splice删除一个元素,并且添加一个元素
this.people.splice(0, 1, {
create: Date.now(),
name: "我修改了数据",
sex: "女",
age: 15
})
},
AddAttr(){
this.$set(this.objs,"hobby","打代码")
},
DeleteAttr(){
//方法1:
//(target, key)target: 可以是对象或数组,key : 可以是字符串或数字
//this.$delete(this.objs,"sex")
//方法2:
let _obj = {...this.objs}; // ... 扩展运算符这里用于复制对象
delete _obj.age;
this.objs = {..._obj};
},
UpdateAttr(){
this.objs.age = 18
}
}
}
</script>渲染结果:
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<div>
<h1>事件绑定v-on</h1>
<h2>操作数组</h2>
<div>当前number:1</div>
<button>点我number加一哟</button>
<button>点我number减一哟</button>
<button>点我number减2哟</button>
<div>我是v-if</div>
<button>切换isShow的值</button>
<ul style="text-align: left;">
<li>zykj - 男 - 18</li>
<li>skx - 男 - 16</li>
<li>y - 女 - 19</li></ul>
<button>添加一个人</button>
<button>删除一个人</button>
<button>更新一个人</button>
<p>----------------------------------------------------</p>
<h2>操作对象</h2>
<ul>
<li>0 - name - zykj</li>
<li>1 - sex - 男</li>
<li>2 - age - 18</li>
</ul>
<button>添加属性</button>
<button>删除属性</button>
<button>修改属性</button>
</div>
事件修饰符
修饰符
在事件处理程序中调用
event.preventDefault()
或event.stopPropagation()
是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。为了解决这个问题,Vue.js 为
v-on
提供了事件修饰符。修饰符是由点开头的指令后缀来表示的。
.stop
- 调用event.stopPropagation()
。阻止冒泡。 例:v-on:click.stop="xxx" , v-on:submit.stop="xxx"
.prevent
- 调用event.preventDefault()
。 阻止默认行为。.capture
- 添加事件侦听器时使用捕获模式
。 两种模式捕获模式
和冒泡模式
.self
- 只当事件是从侦听器绑定的元素本身触发时才触发回调。.native
- 监听组件根元素的原生事件。用于自定义控件。也就是说在自定义组件中添加事件需要加上.once
- 只触发一次回调。.left
- (2.2.0) 只当点击鼠标左键时触发。.right
- (2.2.0) 只当点击鼠标右键时触发。.middle
- (2.2.0) 只当点击鼠标中键时触发。.passive
- (2.3.0) 以 { passive: true } 模式添加侦听器、passive这个修饰符会执行默认方法原因:浏览器只有等内核线程执行到事件监听器对应的JavaScript代码时,才能知道内部是否会调用preventDefault函数来阻止事件的默认行为,所以浏览器本身是没有办法对这种场景进行优化的。这种场景下,用户的手势事件无法快速产生,会导致页面无法快速执行滑动逻辑,从而让用户感觉到页面卡顿。
通俗点说就是每次事件产生,浏览器都会去查询一下是否有preventDefault阻止该次事件的默认动作。我们加上passive就是为了告诉浏览器,不用查询了,我们没用preventDefault阻止默认动作。
这里一般用在滚动监听,@scoll,@touchmove 。因为滚动监听过程中,移动每个像素都会产生一次事件,每次都使用内核线程查询prevent会使滑动卡顿。我们通过passive将内核线程查询跳过,可以大大提升滑动的流畅度。
注:passive和prevent冲突,不能同时绑定在一个监听器上。
键盘事件
基本语法
@key(down/up).[对应的键(可选)]="函数名"
例:@keydown="Key"
@keyup.ctrl="KeyCtrl"
常用的按键修饰符:
1
2
3
4.enter | .tab | .delete | .esc
.space | .up | .down | .left | .right
.ctrl | .alt | .shift | .meta
.键值1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19Ctrl<input @keydown.ctrl="KeyCtrl" type="text" />
Submit <input @keydown.enter="SubmitEvent" type="text" />
Space <input @keydown.space="SpaceEvent" type="text" />
Delete <input @keydown.delete="DeleteEvent" type="text"/>
methods: {
KeyCtrl(){
console.log("点击了Ctrl")
},
SubmitEvent(){
console.log("进行提交")
},
SpaceEvent(){
console.log("按了空格")
},
DeleteEvent(){
console.log("点了删除")
}
}
示例
查看代码
1 | <template> |
渲染结果:
1 | <div> |
计算属性与侦听属性
参考资料:详解Vue计算属性和侦听属性
计算属性
计算属性(computed)是自动监听依赖值
的变化,从而动态返回内容,监听是一个过程,在监听的值变化时,可以触发一个回调,并做一些事情。它有以下几个特点:
- 数据可以进行逻辑处理,减少模板中计算逻辑。
- 对计算属性中的数据进行监视
- 依赖固定的数据类型(响应式数据)
计算属性由两部分组成:get
和set
,分别用来获取计算属性和设置计算属性。默认只有get
,如果需要set,要自己添加。另外set设置属性,并不是直接修改计算属性,而是修改它的依赖。
1 | <div>{{ fullName }}</div> |
同个修改 fullName 时,setter 会被调用,firstName 和 lastName 也会相应地被更新。
计算属性
与普通属性
的区别:可以像绑定普通属性一样在模板中绑定计算属性,在定义上有区别:计算属性的属性值必须是一个函数。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15data:{
//普通属性
msg:'哈哈哈',
},
computed:{
//计算属性
msg1:function(){
//该函数必须有返回值,用来获取属性,称为get函数
return '哈哈哈';
},
reverseMsg:function(){
//可以包含逻辑处理操作,同时reverseMsg依赖于msg,一旦msg发生变化,reverseMsg也会跟着变化
return this.msg.split(' ').reverse().join(' ');
}
}计算属性
与方法
的区别:两者最主要的区别:computed 是可以缓存的,methods 不能缓存;只要相关依赖没有改变,多次访问计算属性得到的值是之前缓存的计算结果,不会多次执行。下面代码看方法和计算属性执行次数:结果:
getFullName() 执行2次
fullName 执行1次
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<div>{{ fullName }}</div>
<div>{{ fullName }}</div>
<div>{{ getFullName() }}</div>
<div>{{ getFullName() }}</div>
var vue = new Vue({
data() {
return {
firstName: "卓越",
lastName: "科技"
}
},
methods: {
getFullName(){
console.log("------getFullName------")
return this.firstName + " " + this.lastName;
}
},
computed: {
fullName: {
get() {
console.log("------fullName------")
return this.firstName + " " + this.lastName;
}
}
}
})
侦听属性
有的时候,我们需要的派生数据是通过异步的方式处理的,这个时候,计算属性就不太好用了(不能处理异步)。我们可以使用另外一个选项:watch
watch : 侦听属性;监听的是data的属性,当属性发生改变以后,会做的一些事情
里面传一个函数,第一个参数是
最新的值
,第二个参数是修改前的值
1
2
3
4
5watch:{
data中的属性名:function(newVal,oldVal){
console.log(newVal,oldVal)
}
}深度监听: 如果监听了对象,当这个对象中的属性名对应的键值对发生改变以后,并不会触发监听的这个对象的函数;因为这个引用数据类型的地址没发生改变;
这个时候需要把watch监听的方法改成对象的写法
handler 相当于函数
deep:true
,对这个对象中的每一个属性进行监听immediate:true
, 可以让函数立即执行一次;当其中一个属性发生改变,也会触发handler这个函数;1
2
3
4
5
6
7
8
9watch:{
data中的属性名: {
handler(){
},
//immediate表示在watch中首次绑定的时候,是否执行handler,值为true则表示在watch中声明的时候,就立即执行handler方法,值为false,则和一般使用watch一样,在数据发生变化的时候才执行handler。
immediate:true
}
}监听对象的时候写在handler方法的参数只写一个就可以,这个参数代表改变之后的值
如果想监听对象里的一个属性值可以写成
对象.属性名
,这个时候写在handler方法的参数就得写两个,
第一个参数是最新的值,第二个参是修改前的值另一种添加监视的方法:
vm.$watch("XX",function(value){})
示例
查看代码
1 | <template> |
渲染结果:
1 | <div> |
双向绑定 v-model
本质: 它负责监听用户的输入事件,从而更新数据,并对一些极端场景进行一些特殊处理。同时,v-model会忽略所有表单元素的value、checked、selected特性的初始值,它总是将vue实例中的数据作为数据来源。 然后当输入事件发生时,实时更新vue实例中的数据。
基本语法
v-model="data中的键名"
1 | <input type="text" v-model="msg"> |
v-model修饰符
.lazy
在输入框失去焦点或者按回车键时才会更新值。.number
输入框输入的内容,即使是数字,默认也是 string 类型,使用 .number 修饰符让其转换为 number 类型.trim
自动过滤掉输入框的首尾空格
示例
查看代码
1 | <template> |
渲染结果:
1 | <div> |
过滤器
过滤器,过滤就是一个数据经过了这个过滤之后出来另一样东西,可以是从中取得你想要的,或者给那个数据添加点什么装饰,那么过滤器则是过滤的工具。
过滤器分为两种:全局过滤器
和局部过滤器
全局过滤器:
全局过滤器必须写在vue实例创建之前
1
2
3
4
5
6//过滤器一:(使用时没有参数,即{{ msg | 过滤器名字}})
Vue.filter('过滤器名字', function (value) {
//可以理解为需要过滤的值
console.log(value);
return value + "-----";
})局部过滤器:
在组件实例对象里挂载
1
2
3
4
5
6//过滤器二:(使用时有参数,即{{ msg | filterA("1","2")}})
filters: {
filterA:(val,msg1,msg2)=>{
return value + msg1 + msg2;
}
}参数说明
1
2
3一:(使用时没有参数,即{{ msg | 过滤器名字}})
二:(使用时有参数,即{{ msg | filterA("1","2")}})使用方法
在双花括号插值
1
{{ msg | filter }}
在v-bind表达式中使用
1
<div v-bind:data="'ok' | globalFilter" ></div>
通过逗号形式
1
2
3
4
5
6
7{{ 'a','b' | filterB }} )
filters: {
filterB:(msg1,msg2)=>{
return msg1 + msg2; //ab
}
}
后续补充更多知识。。。
参考资料: