Vue基础0 - 基本语法

模版语法

缩写

v-bind

1
2
3
4
5
<!-- 完整语法 -->
<a v-bind:href="url">...</a>

<!-- 缩写 -->
<a :href="url">...</a>

v-on

1
2
3
4
5
<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>

<!-- 缩写 -->
<a @click="doSomething">...</a>

获取DOM

1
<div ref="jsbg"></div>

获取

1
const jsbg = this.$refs.jsbg;

模版取值

文本

1
<span>Message: {{ msg }}</span>

表达式

1
2
3
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}

html

双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用 v-html 指令:

1
<p>Using v-html directive: <span v-html="rawHtml"></span></p>

判断

1
2
3
4
5
6
7
8
9
10
11
12
<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>

循环遍历

遍历数字

1
<li v-for="(item,index) in 10">{{item}}</li>

编历一个数字时item的值是从1 始的。
编历一个指定数字也就是相当编历一个从1到指定数字的数组。

所以上面这个例子的item是1-10,index是0-9

遍历对象数组

数据

1
2
3
4
5
6
7
data:{
items:[
{text:"第一组"},
{text:"第二组"},
{text:"第三组"},
]
}

页面

1
2
3
4
5
<li v-for="item in items">{{item.text}}</li>

<li v-for="(item, index) in items">
{{ index }} - {{ item.text }}
</li>

事件

methods

1
<button type="button" v-on:click="loginAction()">登录</button>

对应的方法

1
2
3
4
5
methods:{
loginAction:function(){

}
}

表单提交

1
2
3
4
<form @submit.prevent="submit($event)">
<input type="text" class="form-control" placeholder="请输入姓名" name="username">
<input type="submit" value="登陆" class="login" />
</form>

方法

1
2
3
4
submit: function(event) {
var formData = new FormData(event.target);
console.log(formData.get("username"));
}

事件修饰符

事件修饰符详解

在事件处理程序中调用 event.preventDefault()event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。

为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。

  • .stop
  • .prevent
  • .capture
  • .self
  • .once
  • .passive
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!-- 阻止单击事件继续传播 -->
<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>

<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>

属性相关

computed

1
2
3
4
5
6
7
8
9
data: {
num1: 10,
num2:2
},
computed: {
sum: function () {
return this.num1+this.num2;
}
}

如上 计算属性sum的值就会为3

computed特点:

  1. computed计算的性能更高,它会把计算的值缓存起来,如果data中的属性不变,computed就不会再次计算,而methods中每次都要重新计算
  2. watch主要用于监控vue实例的变化,它监控的变量当然必须在data里面声明才可以,它可以监控一个变量,也可以是一个对象

watch

1
2
3
4
5
6
7
watch: {
// 如果 `question` 发生改变,这个函数就会运行
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.debouncedGetAnswer()
}
}

添加上immediate: true可以让页面初始化时触发了一次监听的事件,默认是不触发的。

1
2
3
4
5
6
7
8
9
10
11
watch: {
"$route.query.id": {
handler: "pageLoad", //调用方法
immediate: true, //进入立即执行一次
},
},
methods: {
pageLoad() {
console.info(this.$route.query.id);
},
}

监听对象

使用deep属性,如果queryData对象内发生了变化就会触发该方法

1
2
3
4
5
6
7
8
watch: {
queryData: {
handler: function() {
//do something
},
deep: true
}
}

监听props不生效

自定义组件中监听props不生效的解决方法

1
2
3
4
5
6
7
8
9
10
11
props: {
numlist: {
type: Array,
default() {
return []
}
}
},
created() {
this.$set(this.numlist)
}

有人说添加上immediate: true就行,但是实际上并不生效,immediate只是让页面初始化时触发了一次监听的事件。

1
2
3
4
5
6
7
8
watch: {
"numlist": {
handler: function () {
console.info("numlist改变了");
},
immediate: true
}
},

所以上述代码是无效的。

filters

JS中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var user_vue = new Vue({
el: ".user",
data: {
loginuser: {username:"我的名称比较长"}
},
filters: {
nameFilter(name) {
if (name.length > 4) {
name = name.substring(0, 4);
}
return name;
}
}
});

取值方式:

1
{{loginuser.username|nameFilter}}

样式

1
v-bind:class="{ unclickable: page == 1 }"

或者

1
:style="{ color: activeColor, fontSize: fontSize + 'px' }"

私有样式

1
2
<style type="text/css" scoped>
</style>

引用样式

1
<style src="../assets/css/style.css" scoped></style>

下面的这中方式是有问题的 scoped会失效

1
2
3
<style scoped>
@import "~@/assets/css/style.css";
</style>

全局

全局方法

扩展

1
2
3
4
5
Vue.prototype.common = {
abc:function(){

}
}

调用

1
this.common.abc();

全局过滤器

1
2
3
4
5
Vue.filter('capitalize', function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})

调用

1
{{ message | capitalize }}

过滤器可以串联:

1
{{ message | filterA | filterB }}

技巧

刷新时不显示模版

当vue需要加载数据多或者网络慢时,加载数据时候会先出现vue模板(例如item.name),用户体验特别不好

解决方法有如下几种:

1、可以通过VUE内置的指令v-cloak解决这个问题(推荐) 具体实现:

CSS中添加样式

1
2
3
[v-cloak] {
display: none !important;
}

页面要渲染的额部分添加v-cloak

1
2
3
<ul v-cloak v-for="item in items">
<li>{{ item.name }}</li>
</ul>

2、可以在需要编译的元素前后加上

1
<template></template>

关于<template> 详解

不推荐第二种 在IE中不支持

DOM渲染后事件

nextTick方法,意思是在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

1
2
3
this.$nextTick(function(){

});

图片绑定

静态绑定图片地址 我们这样写

1
<img src="../../../assets/classtools/practice/opt_danxuan.png" />

动态绑定图片的src时 要这样写才生效

1
<img :src="opttype.img" />

数据

1
2
3
4
5
6
7
// 引用
import opt_danxuan from "../../../assets/classtools/practice/opt_danxuan.png";

// data
{
img:opt_danxuan
}

下面的写法是不行的,因为图片的路径会被当做字符串而非路径,在打包时不会动态改变

1
2
3
{
img:"../../../assets/classtools/practice/opt_danxuan.png"
}

可以看一下打包后的路径进行填写

1
2
3
{
img:"/assets/img/opt_danxuan.png"
}

图片名字尽可能保持不同,打包的时候无论是否建过文件夹在放的图片都会被放在同样的路径。

路径中的@

@是webpack设置的路径别名
@代表着到src这个文件夹的路径

比如上面的路劲就可以写作

1
import opt_danxuan from "@/assets/classtools/practice/opt_danxuan.png";

这样写的时候开发工具不会自动提示路径了,同时如果移动文件的路径也不会自动更新,所以我个人不喜欢这种方式。

引用自己的JS

引用组件

utils.js

1
2
3
4
5
6
7
8
export const arrayContain = function (array, obj){
for (var i = 0; i < array.length; i++){
if (array[i] == obj){//如果要求数据类型也一致,这里可使用恒等号===
return true;
}
}
return false;
}

如果想引用这个方法,就通过import引入

1
import {arrayContain} from '../../js/utils';

组件JS分离

1
<script src="@/assets/js/home"></script>

引用自己的CSS

局部引用

引入方式

1
<style src="@/assets/less/main.less" lang="less" scoped></style>

下面的方式会导致污染

在vue文件中的<style>内填写需要引用的文件

1
2
3
<style scoped lang="less">
@import "@/assets/less/main.less";
</style>

注意

使用@import引入样式文件,就算加scoped,其它没有引入的模块还是可以访问到你的样式,如果某个组件的类名一致,则就会被污染到。

全局引入

main.js

1
import './assets/css/common.css'

生命周期

20181129154348621112493.png

beforeCreate

在实例初始化之后,数据观测(data observer) 和 event/watcher 事件配置之前被调用。

created

实例已经创建完成之后被调用。在这一步,实例已完成以下的配置:数据观测(data observer),属性和方法的运算, watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前不可见。

beforeMount

在挂载开始之前被调用:相关的 render 函数首次被调用。

mounted

el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子。

Ajax请求数据在此阶段

beforeUpdate

数据更新时调用,发生在虚拟 DOM 重新渲染和打补丁之前。 你可以在这个钩子中进一步地更改状态,这不会触发附加的重渲染过程。

updated

由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。

当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态,因为这可能会导致更新无限循环。

该钩子在服务器端渲染期间不被调用。

beforeDestroy

实例销毁之前调用。在这一步,实例仍然完全可用。

destroyed

Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。 该钩子在服务器端渲染期间不被调用。