avatar

目录
Vue-学习笔记

.vue

在.vue文件中,template使用插值表达式的方法可以省略this

Vue基础

Vue实例

  • el:指向一个模块的id
  • data:实例的一些数据,可通过v-model来实现双向数据绑定
  • methods:实例的一些方法, 通过v-on:event来调用
  • watch:用来监视data里的数据,数据变化就会触发对应的函数
    • 语法:dataName: function(){}
  • computed:计算属性
    • 在引用的时候,一定不要加()
    • 只要计算属性,这个function内部所用到的任何data中的数据变化,就会立刻重新计算值.
    • 计算属性的值会被缓存起来,方便下次使用;如果计算属性里的值没有发生变化,则不会重新计算值,节省性能
    • 计算属性里的函数必须return值
  • directive:私有指令
  • component: 私有模板
  • 各种生命周期的钩子
  • render:function(createElement){}
    • createElement是一个方法,调用他,能够把指定的模板组件,渲染为HTML
    • 用法: return createElement(component)
      • 这里会把el指定的模块给替换掉

常用指令

v-if和v-show

  • v-if是把元素从页面中删除/添加,v-show是通过display属性来显示/隐藏
  • v-if 有较高的切换性能消耗 ,不推荐和v-for一起使用
  • v-show有较高的初始渲染消耗
  • 如果元素涉及到频繁的切换,最好不要使用v-if, 而是推荐使用 v-show
  • 如果元素可能永远也不会被显示出来被用户看到,则推荐使用 v-if

v-bind:提供的绑定属性的指令

  • v-bind: 指令可以被简写为 :
  • 用法: v-bind绑定的属性(title,value)
  • v-bind中,可以写合法的JS表达式

v-on:提供绑定事件的指令

  • v-on: 指令可以被简写为 @
  • 用法: v-on:事件=“方法名()”
  • 如果需要拿到event对象则写方法的时候不要夹()

v-for

  • v-for循环的时候,key属性只能使用number
    • key在使用的时候,必须使用v-bind属性绑定的形式,指定key的值
    • 在组件中,使用v-for循环的时候,或者在一些特殊情况中,如果v-for有问题,必须在使用v-for的同是,指定唯一的 字符串/数字类型的key

v-html

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

v-once

  • <span v-once>这个将不会改变: </span>

  • 通过使用 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新。但请留心这会影响到该节点上的其它数据绑定:

动态参数

从 2.6.0 开始,可以用方括号括起来的 JavaScript 表达式作为一个指令的参数:

比如

Javascript
1
2
3
4
5
6
7
data: {
attr: "href"
}
// 把data里的attr动态解析成了字符串
<a v-bind:[attr]="www.baidu.com">baidu</a>
// 相当于
<a v-bind:href="www.baidu.com">baidu</a>

事件

通过v-on:事件来进行绑定

也可以简写@事件来进行绑定

事件修饰符

  • .stop 阻止冒泡
  • .prevent 阻止默认事件
  • .passive 会立即触发,修饰符尤其能够提升移动端的性能
  • .capture 添加事件监听器,使用事件优先捕获
  • .self 只当事件在该元素本身(比如不是子元素)触发时触发
  • .once 事件只触发一次
  • 事件修饰符可叠加使用:v-on:click.stop.once="";

键盘值修饰符

按键码

语法:@keyup.13

Vue 提供了绝大多数常用的按键码的别名:

.enter .tab .delete .esc .space .left .down
.ctrl .alt .shift .meta(window键) .up .right

.exact 修饰符允许你控制由精确的系统修饰符组合触发的事件。

Code
1
2
3
4
5
6
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button v-on:click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button v-on:click.ctrl.exact="onCtrlClick">A</button>
<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button v-on:click.exact="onClick">A</button>

你还可以通过全局 config.keyCodes 对象自定义按键修饰符别名Vue.config.keyCodes.f1 = 112

鼠标修饰符

  • left
  • right
  • midden

案例:用watch来监视url地址的变化

数据绑定

当v-model的值更value的一致时就会被选中

Code
1
2
3
4
5
6
7
8
9
10
<div id='example-3'>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
</div>

修饰符

.lazy

在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy 修饰符,从而转为在 change 事件_之后_进行同步:

Code
1
2
<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg">

.number

如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:

Code
1
<input v-model.number="age" type="number">

这通常很有用,因为即使在 type="number" 时,HTML 输入元素的值也总会返回字符串。如果这个值无法被 parseFloat() 解析,则会返回原始的值。

.trim

如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:

Code
1
<input v-model.trim="msg">

自定义指令

除了核心功能默认内置的指令 (v-modelv-show),Vue 也允许注册自定义指令。注意,在 Vue2.0 中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。举个聚焦输入框的例子

当页面加载时,该元素将获得焦点 (注意:autofocus 在移动版 Safari 上不工作)。事实上,只要你在打开这个页面后还没点击过任何内容,这个输入框就应当还是处于聚焦状态。现在让我们用指令来实现这个功能:

全局指令

  • Vue.directive(“”)

    • 写之定义指令是必须写在实例前

    • 使用Vue.directive() 定义全局指令

    • 注意:指令的名称,注意,在定义的时候,指令名称前面不需要加v-前缀,但是在调用的时候,必须在指令名称前加上v-前缀来进行调用

指令里的三个方法:

  • bind
    • 每当指令绑定到元素上时候,会立即执行这个bind函数,只执行一次
  • inserted
    • inserted表示元素插入到DEMO中的时候,会执行inserted函数(触发1次)
  • updated
    • 当VM偶的更新的时候,会执行updated,可能会触发多次

每个方法里的参数:

  • el:指令所绑定的元素,可以用来直接操作 DOM。
  • binding:一个对象,包含以下 property:
    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2
    • oldValue:指令绑定的前一个值,仅在 updatecomponentUpdated 钩子中可用。无论值是否改变都可用。
    • 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:上一个虚拟节点,仅在 updatecomponentUpdated 钩子中可用。****
Javascript
1
2
3
4
5
6
7
8
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})

然后你可以在模板中任何元素上使用新的 v-focus 属性,如下:

html
1
<input v-focus>

私有指令

Javascript
1
2
3
4
5
6
7
8
directives: {
focus: {
// 指令的定义
inserted: function (el) {
el.focus()
}
}
}

计算属性

对数据进行包装

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

Javascript
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 id="example">  
<p>Original message: "{{ message }}"</p>
<p>Computed reversed message: "{{ reversedMessage }}"</p>
</div>


var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
// 计算属性的 getter
reversedMessage: function () {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
})

监听器

虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的侦听器。这就是为什么 Vue 通过 watch 选项提供了一个更通用的方法,来响应数据的变化。当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。

Javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div id="watch-example">
<p>{{ answer }}</p>
</div>


var watchExampleVM = new Vue({
el: '#watch-example',
data: {
question: '',
},
watch: {
// 如果 `question` 发生改变,这个函数就会运行
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.debouncedGetAnswer()
}
},
}

Vue组件

要给组件绑定事件必须加上事件修饰符.native,否则无效

注意:组件必须创建在实例之上,且使用的时候把驼峰命名法换成已-的形式使用

全局组件

返回值类型

  • 使用Vue.extend来创建全局组件
  • 使用Vue.component(“组件的名称”,创建出来的组件);
    • 如果组件的名称有大写则使用驼峰命名法,在使用组件时则用小写用-分隔
Code
1
2
3
4
var com1 = Vue.extend({
template:'<h3>这是第一种方式</h3>'
});
Vue.component("myCom1",com1);

对象方式

  • Vue.component(“组件的名称”,{});
Code
1
2
3
Vue.component("addComponent",{
template: `<div><p>我是add组件</p> </div>`,
})

模板

  • 让template属性指向一个模板,并且在Vue实例的外面
Code
1
2
3
4
<template id="template"></template>
Vue.component("mycom1",{
template:'#template'
});

.vue文件

  • 一个.vue文件就是一个组件,这种方式用的也比较多
Code
1
2
3
<template></template>
<script></script>
<style></style>

私有组件

在Vue实例中里的component对象里定义

组件也可以有自己的data属性,但是data里一个函数,却必须要返回值,返回一个对象,插入形式跟data插值一样

将vue文件作为组件

javascript
1
2
3
import dialogComponent from "./components/dialog.vue";

Vue.component("dialogGroup",dialogComponent)

组件的切换

tab选项卡时会比较方便

Javascript
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
<template>
<p id="app">
<component :is="currentView"></component>
<button @click="changeView('A')">切换到A</button>
<button @click="changeView('B')">切换到B</button>
<button @click="changeView('C')">切换到C</button>
</p>
</template>

<script>
var app = new Vue({
el: '#app',
data: {
currentView: 'comA'
},
methods: {
changeView: function(data){
this.currentView = 'com'+ data  //动态地改变currentView的值就可以动态挂载组件了。
}
},
components: {
comA: {
template: '<p>组件A</p>'
},
comB: {
template: '<p>组件B</p>'
},
comC: {
template: '<p>组件C</p>'
}
}
});
</script>

组件之间的传值

  • 向子组件传递参数
    • 通过props来传值
  • 向子组件传递方法
    • 用组件生成的标签通过v-on:接收名=”父方法”
      • 父方法里面千万不要加()
    • 在methods里的方法调用this里挂载的$emit(“接收名”,arg1,arg2….)
  • 通过给标签添加ref属性,可在this.$refs中找到对应的dom元素

父组件向子组件传值

javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 父组件
<template>
<childCompoent :parentMessage="name">
<template>
<script>
export default {
data(){
return {
name: "zrb"
}
}

}
</script>

// 子组件
<script>
export default {
props:["parentMessage"] // this._props.parentMessage
}
</script>

子组件向父组件传值:

javascript
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
// 父组件
<template>
<childCompoent @giveParentMessage="getChildMessage">
<template>
<script>
export default {
methods:{
getChildMessage(data){
console.log(`获取到子组件的信息${data}`)
}
}

}
</script>

// 子组件
<script>
export default {
methods:{
Prent(){
this.$emit("giveParentMessage",data)
}
}
}
</script>

插槽

和 HTML 元素一样,我们经常需要向一个组件传递内容,像这样:

Javascript
1
2
3
<alert-box>
Something bad happened.
</alert-box>

幸好,Vue 自定义的 <slot> 元素让这变得非常简单:

Javascript
1
2
3
4
5
6
7
8
Vue.component('alert-box', {
template: `
<div class="demo-alert-box">
<strong>Error!</strong>
<slot></slot>
</div>
`
})

2.6新增写法:

Code
1
2
3
<template v-slot:content></template>
2.6新增
<template #content></template>

基础组件的自动化全局注册

可能你的许多组件只是包裹了一个输入框或按钮之类的元素,是相对通用的。我们有时候会把它们称为基础组件,它们会在各个组件中被频繁的用到。

所以会导致很多组件里都会有一个包含基础组件的长列表:

Javascript
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
import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'

const requireComponent = require.context(
// 其组件目录的相对路径
'./components',
// 是否查询其子目录
false,
// 匹配基础组件文件名的正则表达式
/Base[A-Z]\w+\.(vue|js)$/
)

requireComponent.keys().forEach(fileName => {
// 获取组件配置
const componentConfig = requireComponent(fileName)

// 获取组件的 PascalCase 命名
const componentName = upperFirst(
camelCase(
// 获取和目录深度无关的文件名
fileName
.split('/')
.pop()
.replace(/\.\w+$/, '')
)
)

// 全局注册组件
Vue.component(
componentName,
// 如果这个组件选项是通过 `export default` 导出的,
// 那么就会优先使用 `.default`,
// 否则回退到使用模块的根。
componentConfig.default || componentConfig
)
})

深入组件

data必须是一个函数

取而代之的是,一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:

如果 Vue 没有这条规则,点击一个按钮就可能会像如下代码一样影响到其它所有实例

组件名大小写

使用 kebab-case

  • Vue.component('my-component-name', { /* ... */ })

  • 当使用 kebab-case (短横线分隔命名) 定义一个组件时,你也必须在引用这个自定义元素时使用 kebab-case,例如 <my-component-name>

使用 PascalCase

  • Vue.component('MyComponentName', { /* ... */ })

  • 当使用 PascalCase (首字母大写命名) 定义一个组件时,你在引用这个自定义元素时两种命名法都可以使用。也就是说<my-component-name><MyComponentName> 都是可接受的。注意,尽管如此,直接在 DOM (即非字符串的模板) 中使用时只有 kebab-case 是有效的。

Props大小写

HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:

props类型

到这里,我们只看到了以字符串数组形式列出的 prop:

Javascript
1
props: ['title', 'likes', 'isPublished', 'commentIds', 'author']

但是,通常你希望每个 prop 都有指定的值类型。这时,你可以以对象形式列出 prop,这些 property 的名称和值分别是 prop 各自的名称和类型:

Javascript
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
Vue.component('my-component', {
props: {
// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})

当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。

props单项数据流

所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。

额外的,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。

将原生事件绑定到组件

在有些场景下,我们需要把事件绑定到组件上

这时你就需要用到.native修饰符

例如:

Javascript
1
<base-input v-on:focus.native="onFocus"></base-input>

如果没有.native里面的子组件也想调用传入的方法,可以哦通过$listeners,它是一个对象,里面包含作用在这个组件上的所有监听器

Javascript
1
<bindEvent @click="showAlert"></bindEvent>

子组件可已通过这个获得在组件上绑定的事件

Javascript
1
this.$listeners.click()

.sync

案例:

Javascript
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
<template>
<div class="details">
<myComponent :show.sync='valueChild' style="padding: 30px 20px 30px 5px;border:1px solid #ddd;margin-bottom: 10px;"></myComponent>
<button @click="changeValue">toggle</button>
</div>
</template>
<script>
import Vue from 'vue'
Vue.component('myComponent', {
template: `<div v-if="show">
<p>默认初始值是{{show}},所以是显示的</p>
<button @click.stop="closeDiv">关闭</button>
</div>`,
props:['show'],
methods: {
closeDiv() {
this.$emit('update:show', false); //触发 input 事件,并传入新值
}
}
})
export default{
data(){
return{
valueChild:true,
}
},
methods:{
changeValue(){
this.valueChild = !this.valueChild
}
}
}
</script>

vue 修饰符sync的功能是:当一个子组件改变了一个 prop 的值时,这个变化也会同步到父组件中所绑定。如果我们不用.sync,我们想做上面的那个弹窗功能,我们也可以props传初始值,然后事件监听,实现起来也不算复杂。这里用sync实现,只是给大家提供一个思路,让其明白他的实现原理,可能有其它复杂的功能适用sync。

插槽

Javascript
1
2
3
4
5
6
7
8
9
10
<navigation-link url="/profile">
Your Profile
</navigation-link>

// navigation组件
<div>
<a v-bind:href="url">
<slot></slot>
</a>
</div>

solt标签就会替换成Your Profile,当然也可以传入标签

编译作用域
Javascript
1
2
3
4
5
6
7
8
<navigation-link url="/profile">
Clicking here will send you to: {{ url }}
<!--
这里的 `url` 会是 undefined,因为其 (指该插槽的) 内容是
_传递给_ <navigation-link> 的而不是
在 <navigation-link> 组件 * 内部 * 定义的。
-->
</navigation-link>

这里想拿到父组件传过来的url,但是因为作用域的原因是拿不到的

为一条规则,请记住:

父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。

后备内容
Javascript
1
2
3
<button type="submit">
<slot>Submit</slot>
</button>
具名插槽

注意 v-slot 只能添加在 ` 上 (只有一种例外情况),这一点和已经废弃的 slot attribute 不同。

子组件:

Javascript
1
2
3
4
5
6
7
8
9
10
11
<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>

父组件:

Javascript
1
2
3
4
5
6
7
8
9
10
11
12
<base-layout>
<template v-slot:header>
<h1>Here might be a page title</h1>
</template>

<p>A paragraph for the main content.</p>
<p>And another one.</p>

<template v-slot:footer>
<p>Here's some contact info</p>
</template>
</base-layout>

更具对应的name插入到对应的地方

作用域插槽(以下都没搞懂)

动态组件

之前的案例中有使用componet的is来做tab栏切换

但是在之前的tab切换的时候组件都会重新创建,而不是保存你之前的状态

如果你想保存之前的状态则需要在标签的外层添加<keep-alive>标签包裹起来

Javascript
1
2
3
4
<!-- 失活的组件将会被缓存!-->
<keep-alive>
<component v-bind:is="currentTabComponent"></component>
</keep-alive>

异步组件

Javascript
1
2
3
4
5
6
7
8
Vue.component('async-example', function (resolve, reject) {
setTimeout(function () {
// 向 `resolve` 回调传递组件定义
resolve({
template: '<div>I am async!</div>'
})
}, 1000)
})

组件会在1秒后插入文档里

处理外边界情况

访问根实例

在每个 new Vue 实例的子组件中,其根实例可以通过 $root property 进行访问。

所有的子组件都可以将这个实例作为一个全局 store 来访问或使用。

相当于在子组件能拿到实力上的一些值,对于一些小型的demo来说就可以不适用vuex

访问父组件实例

$root 类似,$parent property 可以用来从一个子组件访问父组件的实例。它提供了一种机会,可以在后期随时触达父级组件,以替代将数据以 prop 的方式传入子组件的方式。

访问子组件实例或子元素
Javascript
1
2
3
4
<base-input ref="usernameInput"></base-input>

可通过访问
this.$refs.usernameInput
依赖注入
程序化的事件监听器
  • 通过 $on(eventName, eventHandler) 侦听一个事件
  • 通过 $once(eventName, eventHandler) 一次性侦听一个事件
  • 通过 $off(eventName, eventHandler) 停止侦听一个事件

这个相当于,你调用this.$emit(eventName,value)之后,你可以在这个组件监听者个的变化就通过上面者三个方法

循环引用
Javascript
1
2
3
4
5
6
7
Vue.component('my-button', {
template: "
<div>
<my-button></my-button>
</div>
"
})

这样子调用会进入一个死循环,可以改造成:

Javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
Vue.component('my-button', {
props: {
count: {
type: Number,
default: 1
}
}
template: "
<div>
<my-button v-if="count++ && count < 3"></my-button>
</div>
"
})
静态组件的开销

渲染普通的 HTML 元素在 Vue 中是非常快速的,但有的时候你可能有一个组件,这个组件包含了大量静态内容。在这种情况下,你可以在根元素上添加 v-once attribute 以确保这些内容只计算一次然后缓存起来,就像这样:

Javascript
1
2
3
4
5
6
7
8
Vue.component('terms-of-service', {
template: `
<div v-once>
<h1>Terms of Service</h1>
... a lot of static content ...
</div>
`
})

案例:切换组件

案例: 切换组件+动画 参考:多个组件的切换

案例:评论去功能,使用本地存储功能,把评论模块写成组件,让子调用父组件

warn: template的属性只能有一个根元素

Vue的生命周期

Vue的生命周期函数不要使用箭头函数来定义,不然可能会报错

Vue的生命周期图

创建阶段

  • beforeCreate:在初始化实例之后,初始化事件和生名周期

    • 到了第一个钩子(beforeCreate)在这个时候,实例里的data和methods中的数据都还没有初始化
  • created:data和methods就已经被初始化好了

  • beforeMount:模板已经在内存中编译好,但是还没渲染到页面中

  • mounted: 整个Vue实例已经初始化完毕了

运行阶段

  • beforeUpdate:当data发生改变时,页面还没有渲染最新的数据
  • updated:页面和data数据已经保持同步了

销毁阶段

  • beforeDestroy

    • beforeDestroy时,实例身上所有的data和methods,以及过滤器,指令等都处于可用状态,此时,还没有真正执行销毁的过程
  • destroed

    • destroyed时,组件已经完全被销毁,此时,组件中的所有的数据,方法,指令,过滤器…都已经不可用了

Vue的HTTP请求

  • vue的Ajax请求是依赖与 vue-resource 或者 axios 包来实现
  • 到了vue2.X版本,vue-resource不再维护,官方推荐的是axios
    • vue-resource
      • 导入包之后,this会挂载一个$http对象
      • 全局也有也会挂在http对象
    • axios
      • 直接axios.get

Vue的动画

把需要做动画的标签外层包一个transition标签

如果元素是有用v-for遍历出来的需要用transition-group来包裹,且元素必须要有:key属性

transition-group标签里的两个属性

  • apper
  • tag

avatar

有四种状态

  • v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
  • v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
  • v-enter-to:在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。
  • v-leave:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
  • v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
  • v-leave-to:在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。

transition标签可以指定name属性,指定完后动画类名的前缀就改成跟name一样

v-enter-activev-leave-active 可以控制进入/离开过渡的不同的缓和曲线

Javascript
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
<template>
<div>
<button @click="show = !show">Toggle</button>
<transition name="fade">
<p v-if="show">hello</p>
</transition>
</div>
</template>

<script>
export default {
data(){
return {
show: true
}
}
}
</script>

<style>
.fade-enter-active,.fade-leave-active {
transition: opacity .5s;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
</style>

自定义过度类名

配合第三方的CSS动画库会比较好

Javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">

<div id="example-3">
<button @click="show = !show">
Toggle render
</button>
<transition
name="custom-classes-transition"
enter-active-class="animated tada"
leave-active-class="animated bounceOutRight"
>
<p v-if="show">hello</p>
</transition>
</div>

显性的过渡持续时间

可以在transition添加duration属性用于执行后的延时

<transition :duration="1000">...</transition>

动画钩子

Javascript
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
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter"
v-on:enter-cancelled="enterCancelled"

v-on:before-leave="beforeLeave"
v-on:leave="leave"
v-on:after-leave="afterLeave"
v-on:leave-cancelled="leaveCancelled"
>
</transition>

methods: {
// 进入中
beforeEnter: function (el) { },
// 当与 CSS 结合使用时
// 回调函数 done 是可选的
enter: function (el, done) {
// ...
done()
},
afterEnter: function (el) { },
enterCancelled: function (el) { },

// 离开时
beforeLeave: function (el) { },
// 当与 CSS 结合使用时
// 回调函数 done 是可选的
leave: function (el, done) {
done()
},
afterLeave: function (el) { },
// leaveCancelled 只用于 v-show 中
leaveCancelled: function (el) { }
}

初始渲染的过渡

可以通过 appear attribute 设置节点在初始渲染的过渡

这里默认和进入/离开过渡一样,同样也可以自定义 CSS 类名。

Javascript
1
2
3
4
5
6
7
8
<transition
appear
appear-class="custom-appear-class"
appear-to-class="custom-appear-to-class" (2.1.8+)
appear-active-class="custom-appear-active-class"
>
<!-- ... -->
</transition>
Javascript
1
2
3
4
5
6
7
8
9
<transition
appear
v-on:before-appear="customBeforeAppearHook"
v-on:appear="customAppearHook"
v-on:after-appear="customAfterAppearHook"
v-on:appear-cancelled="customAppearCancelledHook"
>
<!-- ... -->
</transition>

在上面的例子中,无论是 appear attribute 还是 v-on:appear 钩子都会生成初始渲染过渡。

多个元素的过度

当有相同标签名的元素切换时,需要通过 key attribute 设置唯一的值来标记以让 Vue 区分它们,否则 Vue 为了效率只会替换相同标签内部的内容。

Javascript
1
2
3
4
5
6
7
8
<transition>
<button v-if="isEditing" key="save">
Save
</button>
<button v-else key="edit">
Edit
</button>
</transition>

过度模式

在“on”按钮和“off”按钮的过渡中,两个按钮都被重绘了,一个离开过渡的时候另一个开始进入过渡。这是 `` 的默认行为 - 进入和离开同时发生。

同时生效的进入和离开的过渡不能满足所有要求,所以 Vue 提供了过渡模式

  • in-out:新元素先进行过渡,完成之后当前元素过渡离开。
  • out-in:当前元素先进行过渡,完成之后新元素过渡进入。
Javascript
1
2
3
<transition name="fade" mode="out-in">
<!-- ... the buttons ... -->
</transition>

多个组件的过度

Javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<transition name="component-fade" mode="out-in">
<component v-bind:is="view"></component>
</transition>

new Vue({
el: '#transition-components-demo',
data: {
view: 'v-a'
},
components: {
'v-a': {
template: '<div>Component A</div>'
},
'v-b': {
template: '<div>Component B</div>'
}
}
})

列表过度

案例:购物车小球添加

可复用性

混入

混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。

选项合并

当组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”。

比如,数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先。

浅合并

Javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var mixin = {
data: function () {
return {
message: 'hello',
foo: 'abc'
}
}
}

new Vue({
mixins: [mixin],
data: function () {
return {
message: 'goodbye',
bar: 'def'
}
},
created: function () {
console.log(this.$data)
// => { message: "goodbye", foo: "abc", bar: "def" }
}
})

同名钩子函数将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用。

Javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var mixin = {
created: function () {
console.log('混入对象的钩子被调用')
}
}

new Vue({
mixins: [mixin],
created: function () {
console.log('组件钩子被调用')
}
})

// => "混入对象的钩子被调用"
// => "组件钩子被调用"

值为对象的选项,例如 methodscomponentsdirectives,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对。

浅合并

Javascript
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
var mixin = {
methods: {
foo: function () {
console.log('foo')
},
conflicting: function () {
console.log('from mixin')
}
}
}

var vm = new Vue({
mixins: [mixin],
methods: {
bar: function () {
console.log('bar')
},
conflicting: function () {
console.log('from self')
}
}
})

vm.foo() // => "foo"
vm.bar() // => "bar"
vm.conflicting() // => "from self"

全局混入

混入也可以进行全局注册。使用时格外小心!一旦使用全局混入,它将影响每一个之后创建的 Vue 实例。使用恰当时,这可以用来为自定义选项注入处理逻辑。

Javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 为自定义的选项 'myOption' 注入一个处理器。
Vue.mixin({
created: function () {
var myOption = this.$options.myOption
if (myOption) {
console.log(myOption)
}
}
})

new Vue({
myOption: 'hello!'
})
// => "hello!"

自定义选项合并策略

可以像vm实例添加一些方法

Javascript
1
2
3
4
5
6
7
8
9
10
const merge = Vue.config.optionMergeStrategies.computed
Vue.config.optionMergeStrategies.vuex = function (toVal, fromVal) {
if (!toVal) return fromVal
if (!fromVal) return toVal
return {
getters: merge(toVal.getters, fromVal.getters),
state: merge(toVal.state, fromVal.state),
actions: merge(toVal.actions, fromVal.actions)
}
}

往vm实例添加了vuex方法

插件

插件通常用来为 Vue 添加全局功能。插件的功能范围没有严格的限制——一般有下面几种:

  1. 添加全局方法或者 property。如:vue-custom-element
  2. 添加全局资源:指令/过滤器/过渡等。如 vue-touch
  3. 通过全局混入来添加一些组件选项。如 vue-router
  4. 添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。
  5. 一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如 vue-router

使用插件

通过全局方法 Vue.use() 使用插件。它需要在你调用 new Vue() 启动应用之前完成:

Javascript
1
2
3
4
5
6
// 调用 `MyPlugin.install(Vue)`
Vue.use(MyPlugin, { someOption: true })

new Vue({
// ...组件选项
})

开发插件

Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象:

Javascript
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
MyPlugin.install = function (Vue, options) {
// 1. 添加全局方法或 property
Vue.myGlobalMethod = function () {
// 逻辑...
}

// 2. 添加全局资源
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
// 逻辑...
}
...
})

// 3. 注入组件选项
Vue.mixin({
created: function () {
// 逻辑...
}
...
})

// 4. 添加实例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 逻辑...
}
}

过滤器

Javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script>
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: "#app",
data: {
msg:"曾经,我也是一个单纯的少年,单纯的我,傻傻的问",
},
methods: {},
//定义私用局部过滤器。只能在当前 vue 对象中使用
filters: {
dataFormat(msg) {
return msg.slice(0,10)
},
},
});
</script>

取了msg的前10个字符

路由

通过vue-router包来实现

引入包之后,全局会有 VueRouter的构造函数

函数里的routes的一个数组,数组里存放的是一个对象,对象里有两个必须的属性

  • path: 路由,跳转的地址
  • component: 如果匹配到,则显示相应的模板
  • redirect:默认跳转到,可不加/

指定默认路由也需要有道path,例:{path:"/",rediect:"login"}

跟Vue实例关联:

  1. 通过Vue实例中的router属性来指向VueRouter实例的返回值即可
  2. 如果匹配到路由,有模板,则需要用router-view标清来呈现

router-link

  • 如果觉得<a href="#/login">login</a>太麻烦

  • 可用<router-link to="login"></router-link>来代替,默认渲染为a标签,也可通过tag属性来进行切换

  • active-class 选中时添加的类,可修改

Code
1
2
3
{ path: "/", redirect: "register"},
{ path: "/register", component: registerComponent },
{ path: "/signIn", component: signInComponent },
  • this.$route
    • 用来获取url的参数
    • query:如果想拿到url栏中的查询字符串,可通过this挂载的$route属性来获取
    • params:也可以通过用/:id占位符来得到
  • this.$router

路由的嵌套

如果想在路由底下使用该路由的其他路由
则可以在那个对象匹配规则中加上children数组

数组里在进行匹配规则即可,但是path里不能加/

命名视图

在一个路由规则中可以匹配多个模板把component变成components对象
{viewName: component}

以多个router-view的name来对应

案例1: 字母滚动(熟悉vue)
案例2: 计算器(双向数据绑定)
案例3: 数据列表

Vue API

Vue.mixin

混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。

具体就是跟Vuex一样,只是每个页面的mixin值互不影响

nextTick

nextTick(),是将回调函数延迟在下一次dom更新数据后调用,简单的理解是:当数据更新了,在dom中渲染后,自动执行该函数,

什么时候需要使用nextTick?

Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中,原因是在created()钩子函数执行的时候DOM 其实并未进行任何渲染,而此时进行DOM操作无异于徒劳,所以此处一定要将DOM操作的js代码放进Vue.nextTick()的回调函数中。与之对应的就是mounted钩子函数,因为该钩子函数执行时所有的DOM挂载已完成。

Javascript
1
2
3
4
5
6
created(){
let that=this;
that.$nextTick(function(){ //不使用this.$nextTick()方法会报错
that.$refs.aa.innerHTML="created中更改了按钮内容"; //写入到DOM元素
});
},

Vue的一些第三方包

  • vue-lazyload图片懒加载

vue+webpack

当用import Vue from "vue"时,导入的包是vue.runtime.common.js而不是vue.js

但是我想用component组件却又不想修改导入Vue

解决方案:

  1. 创建.vue的文件,里面有三个标签
    • template
    • script
    • style
  2. 在JS文件中导入.vue文件
  3. webpack不识别除了JS的文件,需要导入包
    • vue-loader
      • 内部依赖:vue-template-compiler
      • 导入方式:
        1. 在webpack配置文件中先引入const VueLoaderPlugin = require('vue-loader/lib/plugin');
        2. 在webpack配置文件中的plugins数组添加new VueLoaderPlugin();
        3. 配置loader
  1. 通过render形式渲染渲染

Vue项目

基本项目目录

Code
1
2
3
4
5
6
7
8
9
10
11
12
|__ vueItem
|__ dist
|__ bundle.js // webpack打包完成后的js
|__ index.html // 主页面
|__ lib // 复制过来的库
|__ src // 放webpack打包的index.js
|__ index.js // 主要逻辑
|__ node_modules // npm下载的包
|__ webpack.config.js // webpack的配置文件
|__ .gitignore // 项目忽略文件,上传到github or gitee时不上传的目录
|__ README.md // 项目说明文件
|__ LICENSE // 开源协议

使用框架

  1. vue
    • vue是主框架
    • version: 2.X
  2. mint-ui
    • 基于vue的移动端框架
  3. webpack
    • 打包工具
    • version:4.41.5

开始

后端系统

question

  1. 控制台报错 “caller”,”callee”,”arguments”控制台报错

  2. 滑动的时候报警告:Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.

  3. 函数内用forEach遍历,结果用return跳不出整个函数

    • forEach是一个函数,跳出的知识forEach的那层函数
      1. 不用forEach
      2. 用一个变量来接收函数是否执行

尝试在手机上访问此页面

  1. 让手机和电脑处于同一个WiFi环境中
  2. 打开package.json文件,在dev脚本中,添加一个指令–host,把但钱电脑wifi的ip设置成host的值

记账软件

question

  1. 屏幕滚动
    1. 给window注册scroll失效
      • 原因;给body设置了height:100%;
    2. 屏幕出现滚动条时,希望页面一直处于最底部,但是获取了window和document.body的scrollTop没用
      • 兼容性的问题
      • 使用document.documentElement.scrollTop || document.body.scrollTop || window.pageYOffset就能获取到
文章作者: 青空
文章链接: https://gitee.com/AIR-ZRB/blog/2020/03/02/Vue-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 青空
打赏
  • 微信
    微信
  • 支付寶
    支付寶