0%

VUE-汇总

学习自:B站up主FastAPIyesAIyes菜鸟教程

为什么要学习vue

为什么要学习vue–为了实现前后端分离,为了实现数据驱动视图,为了减少DOM操作。。。让vue帮我们操作DOM,我们可以更加关注业务逻辑的开发。

未来的发展趋势是前后端只靠json数据进行通信,后端只处理和发送一段json到前端,计算和模板渲染都在前端进行,后台程序不再做模板的任何处理。使用MVVM框架能有效实现前后端的解耦,简化开发流程,便于维护管理,可以把精力更多放到业务逻辑,提升开发效率。

VUE生命周期

  • created

    • 在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图
  • mounted

    • 在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作

vue项目中组件created时,组件中的data和method准备就绪,data中的数据是依赖于axios请求过来的数据的,所以一般在created生命周期函数中发起网络请求

Hello World

Vue.js 的使用有多种方式,可以到官网下载依赖文件使用script标签引用到项目中,也可以使用cdn的方式引入到项目中,或者使用vue-cli创建项目。

vue-cli创建项目

使用vue-cli创建vue项目。

环境搭建

安装node.js,官网:http://nodejs.cn。(历史版本下载:[传送门](https://npm.taobao.org/mirrors/node/))

判断是否安装成功,使用命令:node -v

建议npm配置淘宝源(cnpm):

1
2
3
npm config set registry http://registry.npm.taobao.org/
检查是否更换成功:
npm config get registry

安装cnpm

1
2
npm install -g cnpm --registry=https://registry.npm.taobao.org
判断是否安装成功,使用命令:cnpm -v

创建项目

vue2.x

1
2
3
4
5
6
7
8
9
10
11
12
#安装vue2.x版本的脚手架(若安装失败可以试试管理员权限进行安装,前边加sudo)
cnpm install -g vue-cli
#查看是否安装成功:
vue -V
#卸载
cnpm uninstall -g vue-cli

#创建项目:
vue init webpack 项目名(目录名即项目名)
#启动项目:
[cnpm install - 下载依赖(node文件夹内的依赖)]
cnpm run dev

如何进入某目录打开cmd控制台:地址栏输入cmd后回车或者按住shift键单击鼠标右键选择powershell

案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
qsdbl@qsdbl vue-project % vue init webpack pos	//项目名为pos,vue-project目录专门放vue项目

? Project name pos //直接回车
? Project description A Vue.js project //直接回车
? Author 码代码的冰果果 <1135637451@qq.com> //直接回车
? Vue build standalone //直接回车
? Install vue-router? Yes //我这个项目使用到路由,这里输入yes
? Use ESLint to lint your code? No //不需要
? Set up unit tests No //不需要
? Setup e2e tests with Nightwatch? No //不需要
? Should we run `npm install` for you after the project has been created? (recom
mended) npm //选择npm,刚刚配置了淘宝镜像

vue-cli · Generated "pos".

qsdbl@qsdbl vue-project % cd pos
qsdbl@qsdbl vue-project % cnpm install
qsdbl@qsdbl vue-project % cnpm run dev //启动项目(可能需要使用命令“cnpm install"下载相关依赖)

vue3.x

1
2
3
4
5
6
7
8
9
10
11
12
#安装vue3.x版本的脚手架。若安装失败可以试试管理员权限进行安装,前边加sudo
cnpm install -g @vue/cli
#查看是否安装成功
vue --version
#卸载
cnpm uninstall -g @vue/cli

#创建项目:
vue create 项目名 或 vue ui使用图形化工具
#启动项目:
[cnpm install, 下载依赖(node文件夹内的依赖)]
cnpm run serve

vue管理器:

vue管理器,vue3.x特有。使用vue管理器可以使用图形化界面管理vue项目(创建、删除等)

打开vue管理器,命令行界面中输入命令:vue ui

浏览器输入http://localhost:8000。进入vue管理器:

更多vue3.x创建项目知识,见这篇博客

项目结构

cdn导入vue

对于制作原型或学习,你可以这样使用最新版本:

1
2
3
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<!--或者-->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

对于生产环境,我们推荐链接到一个明确的版本号和构建文件,以避免新版本造成的不可预期的破坏:

1
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>

第一个vue项目:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<!-- 这是View 现在就是templet模板-->
<div id="app">
{{ message }} <!-- 插值表达式,单向数据绑定 -->
</div>
<script>
var vm = new Vue
(
{
el: '#app', // el是元素element的简写,‘#app’是ID选择器方式绑定上面的div节点
// 这里是Model:数据(后端给)
data:
{
message: 'Hello Vue!'
}
// 如果没有mvvm,后端给数据,前端message是不会变化
}
)
</script>
</body>
</html>

创建VUE对象

var vm = new Vue中的Vue,是前边使用cdn导入的js类,使用new创建了一个vue对象。构造方法中传递一个对象(json对象)进去:

  • 其中el对应绑定的元素,可以是html页面中的类名.app、id名#app、元素名div等。这意味着我们接下来的改动全部在指定的元素(标签)内,外部不受影响。
  • data对应绑定的数据,data为一个对象,其中的属性可以有很多。我们自定义一个message属性保存数据”Hello Vue!”。在html中使用插值表达式进行绑定(单向数据绑定)。
    • js中访问data中的message的值,可以使用vm.$data.messagevm.message
    • 原始操作dom的方式:document.querySelector('.app').innerHTML = "你好!👋";
    • 使用vue对象操作dom:vm.message="你好";vm.$data.message="你好";
  • methods 用于定义的函数,可以通过 return 来返回函数值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script>
var vm = new Vue
(
{
el: '#app', // el是元素element的简写,‘#app’是ID选择器方式绑定上面的div节点
// 这里是Model:数据(后端给)
data:
{
message: 'Hello Vue!'
}
// 如果没有mvvm,后端给数据,前端message是不会变化
}
)
</script>

操作data

对比:使用类名(class)绑定元素。将message改成inf。体验原始操作dom的方式和使用vue操作dom。

更多关于操作dom的笔记在后边

打包

部署到生产环境时别忘了使用适用于生产环境vue.js

1、直接用 script 引入

直接下载并用 <script> 标签引入,Vue 会被注册为一个全局变量。

在开发环境下不要使用压缩版本,不然你就失去了所有常见错误相关的警告!

开发版本 包含完整的警告和调试模式

生产版本 删除了警告,33.46KB min+gzip

2、CDN

对于制作原型或学习,你可以这样使用最新版本:

1
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>

对于生产环境,我们推荐链接到一个明确的版本号和构建文件,以避免新版本造成的不可预期的破坏:

1
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>

3、vue-cli

参考这篇博客

vue2.x打包

命令:cnpm run build。打包生成的文件放到根目录的dist文件夹内。

问题1:打包后访问异常

解决方法:将配置文件config/index.js中的assetsPublicPath修改为相对路径(前边加个点即可)。

问题2:打包后icon失效

解决方法: 修改 build/utils.js 中的代码,加入 publicPath: '../../'

1
2
3
4
5
6
7
8
9
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
fallback: 'vue-style-loader',
publicPath: '../../' //解决打包后,图标失效问题
})
} else {
return ['vue-style-loader'].concat(loaders)
}

vue3.x打包

参考资料:

vue官方文档

解决vue-cli项目打包出现空白页和路径错误的问题

vue.config.js publicPath “./“ npm run build无效的原因

命令npm run build

其实yarn run build 与 npm run build 命令作用相同。

注意事项:

打包时,将项目资源访问路径配置为相对路径,打包后的项目可直接以file协议访问站点(双击即可在浏览器访问),方便项目展示。配置与vue2.x项目中的不一样,具体配置如下:

在项目根路径下新建vue.config.js文件,添加以下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module.exports = {
publicPath: './',//相对路径(若要部署在子目录mywebapp(web项目名),则需要改成 /mywebapp/ 。符号“.”表示相对路径)
outputDir: "dist",//打包后的输出路径
assetsDir:"static",//静态文件的存放路径
indexPath:'index.html',//默认打开的html文件
devServer: {//开发环境服务器配置
overlay: {
warnings: false,
errors: false
},
// 设置主机地址
host: 'localhost',
// 设置默认端口
port: 8080
}
}

注意:文件src/router/index.js中的new VueRouter部分,有两个参数需要注意:mode、base。

  • 若publicPath使用的不是相对路径,而是/mywebapp/这种web程序名构成的路径。则这里的参数base也要设置成一样的。
  • publicPath使用的是相对路径,则不需要设置参数base的值,但是mode不建议设置成history。即要去掉该参数。

扩展:关于参数mode。

设置参数mode: 'history',则vue-router使用的是history模式。默认是hash模式,所以想使用hash模式去掉该参数即可。

  • vue-router 使用 hash 模式
    • 将网站部署到服务器直接打开index.html文件即可访问
    • 缺点:地址栏会有“#”。优点:不需要配置。
  • vue-router 使用 history 模式
    • 将网站部署到服务器后,需要进行相关配置才能正常访问。
    • 缺点:配置麻烦。优点:地址栏不会有“#”。

vue案例

登陆/注册案例:传送门

数据绑定

数据绑定有:单向数据绑定、双向数据绑定。详细介绍,查看这篇博客

  • v-bind单向数据绑定。自下而上的单向数据绑定,下是指前端页面看不到的js,上是指展示在页面上的html。(可理解为设置后台数据只读)

    • 绑定标签,使用v-bind
    • 非标签,使用插值表达式(见上边hello world案例中的应用)
    • 详细笔记,访问这里:传送门
  • v-model双向数据绑定,前台更新数据后会立刻更新后台中的数据。(可理解为设置后台数据可读写)

事件绑定

v-on事件绑定。

详细笔记,访问这里:传送门

模板语法

<!–67–>(双大括号)的文本插值

使用 v-html 指令用于输出 html 代码

HTML 属性中的值应使用 v-bind 指令。

以下实例判断 use 的值,如果为 true 使用 class1 类的样式,否则不使用该类:

1
2
3
<div v-bind:class="{'class1': use}">
v-bind:class 指令
</div>

指令

指令是带有 v- 前缀的特殊属性。

指令用于在表达式的值改变时,将某些行为应用到 DOM 上。如下例子:

实例:

1
2
3
4
5
6
7
8
9
10
11
12
<div id="app">
<p v-if="seen">现在你看到我了</p>
</div>

<script>
new Vue({
el: '#app',
data: {
seen: true
}
})
</script>

这里, v-if 指令将根据表达式 seen 的值(true 或 false )来决定是否插入 p 元素。

参数

参数在指令后以冒号指明。例如, v-bind 指令被用来响应地更新 HTML 属性:

1
2
3
4
5
6
7
8
9
10
11
12
<div id="app">
<pre><a v-bind:href="url">菜鸟教程</a></pre>
</div>

<script>
new Vue({
el: '#app',
data: {
url: 'http://www.runoob.com'
}
})
</script>

在这里 href 是参数,告知 v-bind 指令将该元素的 href 属性与表达式 url 的值绑定。

修饰符(后缀)

修饰符是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。例如,.prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault()

1
<form v-on:submit.prevent="onSubmit"></form>

.lazy,焦点改变时触发。

过滤器(管道符)

Vue.js 允许你自定义过滤器,被用作一些常见的文本格式化。由”管道符”指示, 格式如下:

1
2
3
4
5
<!-- 在两个大括号中 -->
{{ message | capitalize }}

<!-- 在 v-bind 指令中 -->
<div v-bind:id="rawId | formatId"></div>

过滤器函数接受表达式的值作为第一个参数。

以下实例对输入的字符串第一个字母转为大写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div id="app">
{{ message | capitalize }}
</div>

<script>
new Vue({
el: '#app',
data: {
message: 'runoob'
},
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
})
</script>

过滤器可以串联:

1
{{ message | filterA | filterB }}

过滤器是 JavaScript 函数,因此可以接受参数:

1
{{ message | filterA('arg1', arg2) }}

这里,message 是第一个参数,字符串 ‘arg1’ 将传给过滤器作为第二个参数, arg2 表达式的值将被求值然后传给过滤器作为第三个参数。

条件语句

if-else

v-if、v-else、v-else-if

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<div id="app">
<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>
</div>

<script>
new Vue({
el: '#app',
data: {
type: 'C'
}
})
</script>

这里, v-if 指令将根据表达式 seen 的值(true 或 false )来决定是否插入 p 元素。

1
2
3
4
<!-- Handlebars 模板 -->
{{#if ok}}
<h1>Yes</h1>
{{/if}}

v-show

1
<h1 v-show="ok">Hello!</h1>

小结

v-show小结:

1、v-show仅仅控制元素的显示方式,通过display属性的none
2、当我们需要经常切换某个元素的显示/隐藏时,使用v-show会更加节省性能上的开销

v-if小结:

1、v-if会控制这个DOM节点的存在与否。
2、如果在运行时条件很少改变,则使用 v-if 较好。

循环-for

v-for 指令

迭代数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div id="app">
<ol>
<li v-for="site in sites">
{{ site }}
</li>
</ol>
</div>
<script>
new Vue({
el: '#app',
data: {
sites: ['Runoob' ,'Google' , 'Taobao','apple' ]
}
})
</script>

迭代对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<div id="app">
<ul>
<li v-for="value in object">
{{ value }}
</li>
</ul>
</div>

<script>
new Vue({
el: '#app',
data: {
object: {
name: '菜鸟教程',
url: 'http://www.runoob.com',
slogan: '学的不仅是技术,更是梦想!'
}
}
})
</script>

迭代整数

1
2
3
4
5
6
7
<div id="app">
<ul>
<li v-for="n in 10">
{{ n }}
</li>
</ul>
</div>

多个参数

可以提供第二个的参数为键名:

1
2
3
4
5
6
7
<div id="app">
<ul>
<li v-for="(value, key) in object">
{{ key }} : {{ value }}
</li>
</ul>
</div>

第三个参数为索引:

1
2
3
4
5
6
7
<div id="app">
<ul>
<li v-for="(value, key, index) in object">
{{ index }}. {{ key }} : {{ value }}
</li>
</ul>
</div>

模板中使用

模板中使用 v-for:

1
2
3
4
5
6
<ul>
<template v-for="site in sites">
<li>{{ site.name }}</li>
<li>--------------</li>
</template>
</ul>

计算属性-computed

计算属性关键词: computed。(跟methods有点相似,但是依赖缓存)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<div id="app">
<p>原始字符串: {{ message }}</p>
<p>计算后反转字符串: {{ reversedMessage }}</p>
</div>

<script>
var vm = new Vue({
el: '#app',
data: {
message: 'Runoob!'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
})
</script>

computed与methods有点相似,但又有所不同:

  • computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 methods ,在重新渲染的时候,函数总会重新调用执行。

  • 可以说使用 computed 性能会更好,但是如果你不希望缓存,你可以使用 methods 属性。

computed与methods的不同点,还体现在getter、setter上。

setter

computed 属性默认只有 getter ,不过在需要时你也可以提供一个 setter :

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 id="app">
<p>{{ site }}</p>
</div>
<script>
var vm = new Vue({
el: '#app',
data: {
name: 'Google',
url: 'http://www.google.com'
},
computed: {
site: {
// getter
get: function () {
return this.name + ' ' + this.url
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.name = names[0]
this.url = names[names.length - 1]
}
}
}
})
// 调用 setter, vm.name 和 vm.url 也会被对应更新
vm.site = '菜鸟教程 http://www.runoob.com';//给computed中的属性site赋值,会调用site中的set方法。
document.write('name: ' + vm.name);
document.write('<br>');
document.write('url: ' + vm.url);
</script>

运行结果:

1
2
3
4
菜鸟教程 http://www.runoob.com

name: 菜鸟教程
url: http://www.runoob.com

监听属性-watch

通过 watch 来响应数据的变化。

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
//在变量kilometers发生改变后调用
watch : {
kilometers:function(new_val,old_val) {//监听变量kilometers,两个参数分别是变化后(新的)与变化前(旧的)的数据。
this.kilometers = new_val;
this.meters = this.kilometers * 1000
}
}

//普通监听:
isCollapse: function(new_val,old_val) {
console.log("new_val:", new_val)
if (new_val.status) {
this.isCollapse.icon = "el-icon-s-unfold";
} else {
this.isCollapse.icon = "el-icon-s-fold";
}
}


//深度监听:
//案例1:
isCollapse:{//深度监听,可监听到对象、数组的变化
handler(new_val, old_val){
if (new_val.status) {
this.isCollapse.icon = "el-icon-s-unfold";
} else {
this.isCollapse.icon = "el-icon-s-fold";
}
},
deep:true //true 深度监听
}

//案例2:指定监听对象中的某个属性(json对象loginForm中的属性username)
'loginForm.username'(newValue, oldValue) { //监听用户名是否被修改
console.log('监听到“用户名”被修改!!!')
。。。
}

https://www.jianshu.com/p/4847b9e3a2c6

监听路由变化

当路由变化后(例如切换到其他页面后又切换回来),再次执行(调用)某个方法。

应用场景:使用keep-alive标签包裹的router-view,在切换路由后会保持页面状态,但我们想在切换路由后更新局部数据时可以使用路由监听。

1
2
3
4
5
6
watch:{
// 如果路由发生变化,再次执行下列方法
"$route": "getGoodsHot",
"$route": "getOrderList",
"$route": "getGoods"
}

搜索

使用监听属性-watch,实现本地搜索功能。

  • 输入框,双向数据绑定mysearch
  • 数组tableData,保存全部数据
  • 数组showTableData,保存要展示出来的数据
  • 监听到变量mysearch变化之后,将与数组tableData中数据匹配的项返回(函数filter),保存在数组showTableData。
    • 注意:数字或对象可以使用JSON.stringify()转换成字符串再进行比对。例如:JSON.stringify(data.goodsList).toLowerCase().inclXXX
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//输入框
<el-input v-model="mysearch" placeholder="请输入关键字" clearable>
<el-button type="primary" slot="append" icon="el-icon-search"></el-button>
</el-input>

//变量
showTableData: [],//展示在表格的数据
tableData: [], //全部数据
mysearch: '', //搜索框输入值

//监听
watch: {
mysearch: function() {
//数组tableData中的元素为对象,remark(备注)、buy_time(购买时间)、price(价格)为对象中包含的属性。(该案例在一采购记录页面截取的)
this.showTableData = this.tableData.filter(data => !this.mysearch || data.remark.toLowerCase().includes(this
.mysearch.toLowerCase()) || data.buy_time.toLowerCase().includes(this.mysearch.toLowerCase()) || data
.price.toLowerCase().includes(this.mysearch.toLowerCase()));
//filter()函数,创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
//toLowerCase()函数,把字符串转换为小写
//includes()函数,判断是否包含某一元素,返回true、false
}
}

样式绑定

Vue.js v-bind 在处理 class 和 style 时, 专门增强了它。表达式的结果类型除了字符串之外,还可以是对象或数组。(菜鸟教程

对象

我们可以为 v-bind:class 设置一个对象,从而动态的切换 class:(对象中可以有多个属性)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div v-bind:class="{ 'active': isActive }"></div>/*isActive的值为true,则应用的类名就等于属性active*/
/*或(属性名最好还是加上单引号)*/
<div v-bind:class="{ active: isActive }"></div>
/*上边的写法,等价于*/
<div class="active"></div>

<script>
new Vue({
el: '#app',
data: {
isActive: true
}
})
</script>

计算属性computed

我们可以在这里绑定返回对象的计算属性(computed)。这是一个常用且强大的模式(将对象放到vue构造器中的计算属性computed中):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div id="app">
<div v-bind:class="classObject"></div>
</div>
<script>
new Vue({
el: '#app',
data: {
isActive: true,
error: {
value: true,
type: 'fatal'
}
},
computed: {
classObject: function () {
return {
base: true,
active: this.isActive && !this.error.value,
'text-danger': this.error.value && this.error.type === 'fatal',
}
}
}
})
</script>

数组语法

我们可以把一个数组传给 v-bind:class ,实例如下:

1
<div v-bind:class="[activeClass, errorClass]"></div>

三元表达式

三元表达式来切换列表中的 class :isActive 为 true 时添加 activeClass 类:

1
2
3
<div v-bind:class="[ isActive ? activeClass : '']"></div>

<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }">菜鸟教程</div>

更多案例见菜鸟教程

事件处理器

详细介绍,查看这篇博客

用法

事件监听可以使用 v-on 指令:(click,点击事件。更多事件类型,访问这里

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div id="app">
<button v-on:click="say('hi')">Say hi</button>
<button v-on:click="say('what')">Say what</button>
</div>
<script>
new Vue({
el: '#app',
methods: {
say: function (message) {
alert(message)
}
}
})
</script>

事件修饰符

Vue.js 为 v-on 提供了事件修饰符来处理 DOM 事件细节,如:event.preventDefault() 或 event.stopPropagation()。

Vue.js 通过由点 . 表示的指令后缀来调用修饰符。

  • .stop - 阻止冒泡
  • .prevent - 阻止默认事件
  • .capture - 阻止捕获
  • .self - 只监听触发该元素的事件
  • .once - 只触发一次
  • .left - 左键事件
  • .right - 右键事件
  • .middle - 中间滚轮事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- 阻止单击事件冒泡 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件侦听器时使用事件捕获模式 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 -->
<div v-on:click.self="doThat">...</div>

<!-- click 事件只能点击一次,2.1.4版本新增 -->
<a v-on:click.once="doThis"></a>

按键修饰符

Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:

1
2
<!-- 只有在 keyCode 是 13 时调用 vm.submit() -->
<input v-on:keyup.13="submit">

记住所有的 keyCode 比较困难,所以 Vue 为最常用的按键提供了别名:

1
2
3
4
<!-- 同上 -->
<input v-on:keyup.enter="submit">
<!-- 缩写语法 -->
<input @keyup.enter="submit">

全部的按键别名:

  • .enter
  • .tab
  • .delete (捕获 “删除” 和 “退格” 键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right
  • .ctrl
  • .alt
  • .shift
  • .meta

实例

1
2
3
4
<p><!-- Alt + C -->
<input @keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>

监听原生事件

1
2
//监听原生事件(添加.native后缀,即事件修饰符)
@dblclick.native="storageDetail(item.id)" //双击触发

扩展

click事件失效

vue的click事件失效。

在移动端,应该使用tap事件代替click事件。还可以使用@touchstart等事件。

组件component

组件一般由三部分组成,template、script、style。template中为html代码。

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
<!-- 组件一般由三部分组成,template、script、style -->
<template>
<div class="pos">
<h1 v-if="isShow">{{msg}}</h1>
</div>
<!-- 必须只能有一个根标签,这里使用div -->
</template>

<script>
export default {
name: 'pos',
data() {
return {
msg: '',
isShow: true
}
},
mounted() {
this.msg = "你好啊👋";
}
}
</script>

<style scoped>
/* 加scope,只有当前页面起作用 */
h1{
color: #28A7FF;
}
</style>

组件即可以作为一个单独的页面也可以作为页面的一部分(有点类似母板页)

作为组件

使用vue-cli构建的vue项目为单页面应用,App.vue就是项目打开的第一个页面。在APP.vue中添加的内容,除非是手动去掉否则会一直存在。

作为单独的页面

在其他组件中(例如app.vue)通过链接<router-link to="/pos">点我,去pos页</router-link>访问(见“作为组件”中的图)。通过router-link加载相应的组件,会渲染在router-view标签的位置(替换)

Vue3.x可以将import语句写在component后边(第12行代码)。

使用vue-cli构建的vue项目为单页面应用,App.vue就是项目打开的第一个页面:

点击router-link链接后,显示pos组件的内容:

案例

下拉刷新组件

使用vue实现的一个下拉刷新组件:https://blog.csdn.net/qq_34439125/article/details/85602508

应用的项目:我的Gitee仓库

1
2
3
4
5
//使用上边的组件报错(浏览器警告。与touch事件有关),可以添加下边的样式:
* {
/* touch-action: pan-y; */
touch-action: none;
}

表单

在表单上应用 v-model , v-model 指令在表单控件元素上创建双向数据绑定。详情见菜鸟教程

v-model的使用

演示 input 和 textarea 元素中使用 v-model 实现双向数据绑定:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<div id="app">
<p>input 元素:</p>
<input v-model="message" placeholder="编辑我……">
<p>消息是: {{ message }}</p>

<p>textarea 元素:</p>
<p style="white-space: pre">{{ message2 }}</p>
<textarea v-model="message2" placeholder="多行文本输入……"></textarea>
</div>

<script>
new Vue({
el: '#app',
data: {
message: 'Runoob',
message2: '菜鸟教程\r\nhttp://www.runoob.com'
}
})
</script>

修饰符

.lazy

在默认情况下, v-model 在 input 事件中同步输入框的值与数据,但你可以添加一个修饰符 lazy ,从而转变为在 change 事件中同步:

1
2
<!-- 在 "change" 而不是 "input" 事件中更新 -->
<input v-model.lazy="msg" >

(失去焦点时才更新数据)

.number

如果想自动将用户的输入值转为 Number 类型(如果原值的转换结果为 NaN 则返回原值),可以添加一个修饰符 number 给 v-model 来处理输入值

.trim

如果要自动过滤用户输入的首尾空格,可以添加 trim 修饰符到 v-model 上过滤输入

操作DOM

认识vm.$refs

在VUE中操作DOM,可以使用document.querySelector(“#id名”)来获取DOM节点,也可以使用VUE提供的vm.$refs来获取DOM节点。

VUE官方文档中关于vm.$refs的介绍:一个对象,持有注册过 ref 属性 的所有 DOM 元素和组件实例。(参考子组件 ref特殊 attribute - ref

什么是ref属性

在使用vm.$refs之前,我们需要先了解一下ref 属性。ref属性接收一个string类型的值,用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例。

我的理解:在使用document.querySelector(“#id名”)来获取DOM节点之前需要给元素添加一个id,同理在使用vm.$refs来获取DOM节点之前需要给元素添加一个ref,有点类似于给元素添加一个标识。

使用ref注意点:

  • v-for 用于元素或组件的时候,引用信息将是包含 DOM 节点或组件实例的数组。(即不是通过vm.$refs.ref名来获取DOM节点,而是通过vm.$refs.ref名[数组索引]

  • 关于 ref 注册时间的重要说明:因为 ref 本身是作为渲染结果被创建的,在初始渲染的时候你不能访问它们 - 它们还不存在!$refs不是响应式的,因此你不应该试图用它在模板中做数据绑定。

    • 我的理解:在页面渲染之后vue才会去注册ref,在此之前不能访问到它们。在访问它们时要确保ref已注册,可以使用$nextTick来确保ref在注册后再访问。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    //$nextTick:在下次 DOM 更新循环结束之后执行延迟回调
    Vue.$nextTick(() => {
    Vue.$refs.myform.resetFields();
    //清空form表单的数据(form表单中注册了ref="myform")
    })

    //下边两种写法是完全相等的:
    this.$refs.myform
    this.$refs['myform']

案例

通过给form表单添加ref属性,在弹出表单之前将表单中的数据清空(使用el-form表单的resetFields()方法)。

  1. 本案例中所使用的页面元素为ElementUI中的el-form。

  2. el-form标签中,添加ref属性。(给页面form表单元素注册引用信息)

    • 注意:若el-form放在v-for中,就不是通过this.$refs.ref名来获取DOM节点,而是通过this.$refs.ref名[数组索引],详情见上边的“ref注意点”。

    • 要使用resetFields()清空表单,el-form-item标签中要添加prop属性。(尽量与form表单绑定的form对象中的属性名相同)

      1
      2
      3
      4
      5
      6
      <el-form :model="form" ref="form">
      <el-form-item prop="mat_name" label="物资名称">
      <el-input v-model="form.mat_name"></el-input>
      </el-form-item>
      ...
      </el-form>
  3. 清空form表单的数据。通过this.$refs.ref名this.$refs['ref名']获取到DOM元素。

    1
    2
    3
    4
    //在触发弹窗的按钮事件中添加如下代码:
    this.$nextTick(() => {
    this.$refs.form.resetFields(); //清空form表单的数据
    })

小技巧

视图更新

问题:数据更新但是视图没有更新。常见于数据是数组或json对象。

解决方法:

  • 调用vue的set()函数更新数据

    1
    vue.$set( target, propertyName/index, value )
  • 使用watch深度监听json对象的属性

  • v-for,遍历的视图,可尝试更改key值触发视图更新

  • 调用vue的forceUpdate()函数,强制更新

  • 最笨的方法,使用v-if销毁再重建

路径

cli项目中@指向src目录。

1
2
3
4
5
6
// 绝对路径,@指向项目根目录,在cli项目中@指向src目录
import add from '@/common/add.js'
// 相对路径:
./ 当前路径
../ 上一级路径
import add from '../../common/add.js'

this关键字

vue回调函数中无法使用this访问vue中数据(data)或方法(methods)的问题:

  • 解决方法一:先用一个变量将this保存在回调函数外边,在回调函数内使用该变量调用vue中的数据

  • 解决方法二:使用箭头函数。this还是指向vue实例。更多笔记,访问MDN web文档

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    (param1, param2, …, paramN) => { statements } 
    (param1, param2, …, paramN) => expression
    //相当于:(param1, param2, …, paramN) =>{ return expression; }

    // 当只有一个参数时,圆括号是可选的:
    (singleParam) => { statements }
    singleParam => { statements }

    // 没有参数的函数应该写成一对圆括号。
    () => { statements }


    //动态获取/设置vue中定义的变量值(field_name,函数传递过来的变量名)
    this.$data[field_name] = '';

定义全局变量

思路有两个:

  • 挂载到原形上
    • 例如:在main.js文件中添加Vue.prototype.$http = axios($符合,是变量名称的一部分。仅仅起到区分全局变量、局部变量的作用。变量可以是普通字符串、json对象等)
  • 单独写在一个配置文件中。可参考这篇博客
  • 使用vuex。

项目样式相关

设置项目的标题、图标、全局样式等。

vue-cli(vue2.x版本)创建的项目,在根目录下有一个index.html文件,要设置标题只需要修改其中的title即可,其他属性也是如此。还可以在该文件中设置一些全局样式,或者新建一个css文件专门设置全局样式。关于全局样式文件的配置可以查看ElementUI笔记中的样式部分。

vue2.x版本中添加全局样式表:

1
2
3
4
//在main.js中,导入全局样式表
import './assets/css/global.css'

//注意:在vue2.x版本中,“./”代表的文件夹为src文件夹。

浏览器调试

使用vue-cli开发项目时,要想在浏览器控制台调试data中的某个变量,需要在钩子函数created中添加如下代码:

1
2
3
4
5
6
7
8
created() {
window.vue = this;//用于浏览器控制台调试使用的变量(在window对象中创建一个变量vue)
}

//同理,若要将vue中定义的方法、属性放到window对象中在vue外边调用也可以这样子配置
created() {
window.scanSucess = this.scanSucess;
}

使用方法,在浏览器控制台中,输入vue即可获取绑定的this实例,vue.$data.变量名可获取某一变量的值。

安装浏览器插件

在chrome安装vue 开发插件。

使用佛跳墙科学上网,打开Chrome插件商店搜索vue devtools安装即可。重新打开开发者工具(快捷键f12或ctrl+fhift+i)即可在开发者工具的菜单栏中看到vue选项卡。

传递参数

方式一:

页面跳转,将要传递的参数拼接在url后边。后边跟参数(baidu.com?key=value),参数之间&隔开(key=value&key2=value2)

新打开的页面中获取传递的参数,方法如下:

1
2
3
4
5
6
//获取地址栏中的参数(?key=value)
getQueryString(name){
var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if(r!=null)return unescape(r[2]); return null;
}

扩展:使用vue-router传递参数。

1
2
3
4
5
6
7
this.$router.push({
name: name,//路由定义中的name
params: {
id: '15324',
age: 18
}//传递参数(会拼接在url后边)
})

方式二:

保存在localStoresessionStore中,使用setItem、getItem、removeItem等函数保存、获取、移除。

注意:保存json对象,需要使用JSON.stringify(json对象)转换为字符串,获取时再使用JSON.parse()函数转换为json对象。

方式三:

定义全局变量,见上边笔记

搜索框

监听输入框的输入事件,当有输入事件发生时调用searchInput函数。使用变量search绑定输入框中输入的数据(双向数据绑定)

1
@input="searchInput"

匹配字段newstitle或newsauthor

1
2
3
4
5
6
7
8
9
searchInput(){
if(this.search == ''){//变量search绑定输入框中输入的数据
this.text = this.text_old;//text_old为全部数据,text为要展示的数据(数组)
}
console.log("监听到输入:"+this.search);
this.text = this.text_old.filter(data=>
data.newstitle.toLowerCase().includes(this.search.toLowerCase()) || data.newsauthor.toLowerCase().includes(this.search.toLowerCase())
)
}//newstitle,newsauthor为text_old中的数据的字段名。includes函数,判断输入的数据search与data对象中的字段newstitle或newsauthor是否有相同的部分(包含)有则返回该data对象,并赋值给text(在页面展示出来)

导入js文件

创建一个js文件(本案例是在与vue文件同级的地方),保存数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//导出一个变量mydata
export const mydata = [{
label: '一级 1',
children: [{
label: '二级 1-1',
children: [{
label: '三级 1-1-1'
}]
}]
}, {
label: '一级 2',
children: [{
label: '二级 2-1',
children: [{
label: '三级 2-1-1'
}]
}, {
label: '二级 2-2',
children: [{
label: '三级 2-2-1'
}]
}]
}]

在vue文件中使用import导入js文件。

1
2
3
4
5
6
7
8
9
10
11
import { mydata } from "./data.js";//"./"表示当前目录,“../”表示上级目录


data() {
return {
title: "物资分类",
data: mydata
};
}

#在js文件中,mydata为一个数组,可直接赋值给变量data

导入本地图片

注意:图片等静态资源(js、css等文件还是建议放在src的assets下,使用import导入),建议放在static目录下(与src同级),使用时用路径“./static/。。。”就无需使用import、require()了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//img标签中使用相对路径可以正常引用 src/assets 下的图片
//但是在vue的data中定义一个变量保存图片的相对路径,通过绑定img的src来控制图片显示时却无效。解决方法是使用import 或 require()
//示例:

//html部分:
<img :src="avatarIcon" />

//js部分:
import myavatarIcon from '../../assets/img/toux0.png';

。。。
data() {
return {
//使用import
avatarIcon: myavatarIcon,
//或者require()
avatarIcon2: require('../../assets/img/toux0.png')
};
}
。。。

更多笔记,见web小技巧

若图片不能正常显示,请在浏览器中打开

欢迎关注我的其它发布渠道