vue实例
- 每个 Vue 应用都是通过用 Vue 函数创建一个新的 Vue 实例 开始的:当创建一个 Vue 实例时,你可以传入一个选项对象。
const vm = new Vue(options)根据options里的内容返回一个vue实例(对象)命名为vm- 这个vm对象封装了对视图的所有操作,包括数据读写、事件绑定、DOM更新
- vue是视图层的框架,没有包含网络层(ajax)
- vm的构造函数是Vue,按照ES6的说法,vm所属的类是Vue
- options(一个对象)是new Vue的参数,一般称之为选项或构造选项(构造函数后面的选项)
组件
-
组件被vue实例使用
-
组件可以由一个vue文件生成,也可以我们声明一个组件(内容和options一模一样,除了data必须用函数)
-
组件名开头大写
options的五类属性
数据
data内部数据props外部数据,也叫属性propsData用不着学computed倍计算出来的methods面向对象的函数,也就是使用时要obj.sayHi()(普通函数sayHi())watch
DOM
el挂载点template在完整版里的视图render在非完整版里的视图,用不着学renderError在非完整版里的视图失败了
生命周期钩子:
beforeCreatecreatedbeforeMountmountedbeforeUpdateupdatedactivateddeactivatedbeforeDestroydestroyederrorCaptured先不看,用到再查文档
资源
directives指令filters过滤器(不要用了),用methods代替components组件,如Demo.vue
组合
parent先不看,用到再查文档mixins混入extends扩展provideinject注入
el--挂载点
你的组件、你的实例的挂载点。(index.html文件提供)
new Vue({
el: "#app"
});
new Vue({}).$mount('#app')提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。可以是 CSS 选择器,也可以是一个 HTMLElement 实例。
在实例挂载之后,元素可以用 vm.$el 访问。
如果在实例化时存在这个选项,实例将立即进入编译过程,否则,需要显式调用 vm.$mount()手动开启编译。
提供的元素只能作为挂载点。不同于 Vue 1.x,所有的挂载元素会被 Vue 生成的 DOM 替换。因此不推荐挂载 root 实例到 <html> 或者 <body> 上。一般情况下el里面的内容是不会被看到的,除非网速特别慢
如果 render 函数和 template 属性都不存在,挂载 DOM 元素的 HTML 会被提取出来用作模板,此时,必须使用 Runtime + Compiler 构建的 Vue 库。
data -- 内部数据
两个用法:对象和函数(函数里返回对象就行了,优先使用函数new Vue({
data() {
return {
n: 0,
array:[1,2,3]
}
}
}).$mount("#app");如果你的data是写在组件中的,那么你的data必须是函数。
当一个组件被定义,data 必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!vue在遇到data是个函数时,会先调用data来获取真正的data。每次调用data得到的对象是不一样的。
var vm = new Vue({
data: { a: 1 }
})var Component = new vue({
data: function () {
return { a: 1 }
}
})Vue 将会递归将 data 的属性转换为 getter/setter,从而让 data 的属性能够响应数据变化。原型上的属性会被忽略。data 应该只能是数据 - 不推荐观察拥有状态行为的对象。
实例创建之后,可以通过 vm.$data 访问原始数据对象。Vue 实例也代理了 data 对象上所有的属性,因此访问 vm.a 等价于访问 vm.$data.a。
methods -方法
- 两个用法
- 事件处理函数
- 普通函数(直接在视图里调用,每一次更新渲染都会调用一次)
import Vue from "vue";
Vue.config.productionTip = false;
new Vue({
data() {
return {
n: 0,
array: [1, 2, 3, 4, 5, 6, 7, 8]
};
},
template: `
<div class=red>
{{n}}
<button @click="add">+1</button> //事件处理函数
<hr>
{{filter()}} //普通函数(直接在视图里调用,每一次更新渲染都会调用一次)
</div>
`,
methods: {
add() {
this.n += 1; //事件处理函数
},
filter() {
return this.array.filter(i => i % 2 === 0); //普通函数
}
}
}).$mount("#app");
methods:
methods 将被混入到 Vue 实例中。可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用。方法中的 this 自动绑定为 Vue 实例。又因为vue实例代理了data里的属性,所有this.n指的就是data里的n。而{{n}}会把n渲染上去
箭头函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。所以method不能用箭头函数
components--Vue组件
组件就是可复用的 Vue 实例,且带有一个名字,我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用:
方法一:推荐使用,很模块化
- 新建一个vue文件Demo.vue,这个vue文件就是一个组件
- 在main.js中引入这个vue文件
- 在vue实例的components中声明这是我要用的组件,并且命名为Demo1
- 这样在这个Vue实例的template中就可以直接使用这个组件
<Demo1/>
import Vue from "vue";
import Demo from "./Demo.vue"; //引入这个vue文件
Vue.config.productionTip = false;
new Vue({
components: {
Demo1: Demo //在vue实例的components中声明这是我要用的组件,并且命名为Demo1
//如果组件名就叫Demo,即Demo:Demo,那就写Demo
//components: {Demo},
},
data() {
return {
n: 0
};
},
template: `
<div class=red>
{{n}}
<button @click="add">+1</button>
<Demo1/> //这样在这个Vue实例的template中就可以直接使用这个组件`<Demo1/>`
</div>
`,
methods: {
add() {
this.n += 1;
},
}
}).$mount("#app");
复制代码方法二:全局
- 在main.js里直接写一个全局组件,写组件名字和内容(内容和options一模一样,除了data必须用函数)
- 直接在任何Vue实例的template中就可以使用这个组件
<Demo2/>
import Vue from "vue";
Vue.config.productionTip = false;
Vue.components('Demo2,{template:`<div>Demo2</div>`}') //在main.js里直接写一个全局组件,写组件名字和内容
new Vue({
data() {
return {
n: 0
};
},
template: `
<div class=red>
{{n}}
<button @click="add">+1</button>
<Demo2/> //直接在任何Vue实例的template中就可以使用这个组件`<Demo2/>`
</div>
`,
methods: {
add() {
this.n += 1;
}
}
}).$mount("#app");
复制代码方法三:上面结合
在vue实例的components中写这个vue实例要用的组件,组件名为Demo3,内容为和options一模一样,除了data必须用函数
import Vue from "vue";
Vue.config.productionTip = false;
new Vue({
components: {
Demo3: { template: `<div>Demo2</div>` } //在vue实例的components中写这个vue实例要用的组件,组件名为Demo3,内容和options一模一样,除了data必须用函数
},
data() {
return {
n: 0
};
},
template: `
<div class=red>
{{n}}
<button @click="add">+1</button>
<Demo3/> //直接在这个Vue实例的template中就可以使用这个组件`<Demo3/>`
</div>
`,
methods: {
add() {
this.n += 1;
}
}
}).$mount("#app");
四个钩子
- created -- 实例出现在内存中后触发
- mounted-- 实例出现在页面中(挂载了)后触发
- updated -- 实例更新了后触发
- destroyed -- 实例从页面和内存中消亡了后触发
- 所有的生命周期钩子自动绑定
this上下文到实例中,因此你可以访问数据,对属性和方法进行运算。写在options里面,注意不是method里面
mouted就是append到页面中,而created是create到内存中,在潜意识里父组件先created,然后子组件created,其实顺序可以是不固定的,
一般情况下是父组件创建,子组件创建,子组件挂靠,父组件挂靠
结论:如果一个组件挂靠了,那么它的所有子孙组件都已经挂靠好了
利用这个结论我们可以在父组件mounted的时候,使用$children访问子组件进行数据绑定,此时子组件已经全部挂靠好(children不是响应式的,且没有顺序)
mounted() {
this.$children.forEach(vm=>{
vm.gutter = this.gutter
})
}
props-外部数据、属性
props 可以是数组或对象,用于接收来自父组件的数据。props 可以是简单的数组,或者使用对象作为替代,对象允许配置高级选项,如类型检测、自定义验证和设置默认值。
message="n"传入字符串:message="n"传入vue实例的this.n数据:fn="add"传入vue实例的this.add函数
一个组件的props指 属性名是我定义在我自己里面,我的template也用到了这些属性,但是属性值是从外面传给我的,上面代码的后两个中的双引号不是js代码的一部分
(所以我自己不能改这个属性值的,属性值是从外面来的,所以我自己就算改了,外面的改了之后我的属性值还是得跟着外面的来。我就是想要修改!请看最下面)
外面咋传给我?外面的Vue实例在引用我这个组件的时候传给我。
Demo.vue
<template>
<div class="red">
这是Demo内部
{{message}} //我要用message
<button @click="fn">点我</button> //我要用fn
</div>
</template>
<script>
export default {
props: ["message", "fn"]
//表示本组件可以接受一个参数message和fn,但是message和fn的值不是从我这里传入的,是外面传给我的。
//所以message和fn就是Demo的外部数据(属性名是我定义在我自己里面,我的template也用到了这些属性,
//但是属性值是从外面传给我的)
};
</script>
<style scoped>
.red{
color: :red;
}
</style>
在main.js里
import Vue from "vue";
import Demo from "./Demo.vue";
Vue.config.productionTip = false;
new Vue({
components: { Demo },
data() {
return { n: 0 };
},
template: `
<div>
<Demo message="n"/> //在引用Demo组件时把他要用的message的值传入,值就为一个字符串n
<Demo :message="n"/> //在引用Demo组件时把他要用的message的值传入,值为这个Vue实例的data里的n
<Demo :fn="f1"/> //在引用Demo组件时把他要用的fn的值传入,值为这个Vue实例的methods里的f1
</div>
`,
methods: {
f1() {
console.log("Hi");
}
}
}).$mount("#app");
props传递的是外部将要传进来的值(另一个组件套用这个组件时传的值),不同于data是内部自己定义的值,在options里面定义好props后,需要在外面(另一个组件)传值
例子(非完整版Vue)
-
组件不可以修改props只能是外部给组件的
-
组件就是想要改它的一个props:money,也就是外部(父组件)给我total
-
可以!你通知外部你想咋改,外部来改,你不也就同时被改了吗
-
怎么通知?eventBus!但在Vue里面是
-
儿子用
$emit触发updata:money事件(同时传参数);{{money}}<button @click="$emit('update:money', money-100)"> -
爸爸在引用儿子的时候用
v-on监听updata:money事件,可以用$event获得那个参数,所以事件处理函数就为把参数给自己的total<Child :money="total" v-on:updata:money="total= $event"/>注意,完全等同于
<Child :money.sync="total"/>(同步)(语法糖)
父亲data的total传给儿子props的money
-
儿子想咋改,写在
$emit的第二个参数里;爸爸就会从v-on里用$event获取$emit的那个参数就知道儿子是想咋改的,爸爸就会把这个结果给自己的total。 当点击的时候,儿子触发'update:money'事件,此时父亲监听到'update:money'事件,调用"total= $event"代码,修改了total
-
爸爸的total改了,儿子的money不就给改了??!!成功
逻辑
@click="$emit('update:money', money-100)"写着行代码时就相当于发布了一个update:money事件,当你点击时触发事件,父亲监听到事件$emit传的参数可以由$event拿到
写一个(子)组件Child.vue
<template>
<div class="child">
{{money}} //儿子这里要显示钱
<button @click="$emit('update:money', money-100)">
//儿子每次点击按钮就是想花钱,可是钱是爸爸给的自己花不了。
//那就每次花钱的时候触发花钱事件update:money,这个事件会把爸爸给的钱-100,也就是儿子想怎么把这个钱花掉
<span>花钱</span>
</button>
</div>
</template>
<script>
export default {
props: ["money"] //儿子需要父亲给钱money
};
</script>
<style>
.child {
border: 3px solid green;
}
</style>
复制代码写一个(父)组件App.vue ,这就是非完整版要用的vue文件
<template>
<div class="app">
App.vue 我现在有 {{total}}
<hr>
<Child :money="total" v-on:updata:money="total= $event"/>
//爸爸在引用儿子的时候,先把自己的钱total给儿子money,在监听儿子的花钱事件updata:money,只要儿子花钱了,就把自己现在的钱total的金额=儿子想怎么花掉这钱$event。爸爸的total变了,儿子的money也变了
//爸爸把total给儿子当他的money,要是儿子想改money就通知爸爸改爸爸的total
</div>
</template>
<script>
import Child from "./Child.vue";
export default {
data() {
return { total: 10000 };
},
components: { Child: Child }
};
</script>
<style>
.app {
border: 3px solid red;
padding: 10px;
}
</style>总结:vue的修饰符sync的功能是:当一个子组件改变了一个 prop 的值时,这个变化也会同步到父组件中所绑定的。sync是个语法糖。他是尤雨溪为我们写的<Child :money="total" v-on:updata:money="total= $event"/>的简写形式。