new Vue(options)
这个options是Vue的参数,一般称之为选项,或构造选项。
一. 入门属性
这里我们改成使用完整版,代码都写到js里,方便看
//main.js
new Vue({
data() {
return { n: 0 };
},
template: `
<div class="red">
{{n}}
<button @click="add">+1</button>
</div>
`,
methods: {
add() {
this.n += 1;
},
},
}).$mount("#app");
//index.html
<div id="app"></div>
1. el
el指定这个实例的挂载点,这个节点的内容会被替换。
//main.js
new Vue({
el: "#app", //对这个div进行MVC封装
});
如果div里有其他内容,也会被替换掉,看不见。
可以用$mount代替:
new Vue({
render(h) {
return h(Demo);
},
}).$mount("#app");
2. data :内部数据
写法支持对象和函数,优先使用函数。
data:{
n:0
}
函数要return
之前我们使用vue-loader时说过,在.vue文件(可以当作一个vue组件)里写的data必须是函数。
import Demo from './Demo.vue'
new Vue({
render(h){
h(Demo)
}
})
Demo是个对象,在render函数里h(Demo)时,其实是把Demo传给了new Vue,也就是new Vue(Demo) 。在第一次传的时候没有错误。但是如果一个组件下边有两个组件,先new一个,再new一个。
这时如果data是个对象,两个组件就共享了一个实例,如果改了其中一个的数据,另一个也会变化。
如果data是函数,需要改数据时Demo发现data是个函数,就会先调用data函数然后得到数据。另一个组件也是先调用,得到值。这种情况下,每次调用data都是得到了一个全新的对象,地址不一样。避免了组件共用一个对象。
3. methods
1. 事件处理函数
把事件处理函数写在methods对象里。如果写在了methods外边,会报错,说该函数没有定义。
2. 普通函数
比如用methos代替vue的filters属性。
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((x) => x % 2 === 0);
},
},
}).$mount("#app");
在页面就会展示 [2,4,6,8]
这就是methods的第二种用法,在模板里主动调用一个函数。但是这种做法有一个问题,只要template里有一处改变了(或每次渲染),就会再次调用这个函数。每点一次+1按钮,filter函数就会被调用一次。哪怕结果和之前一样,也会被调用。
4. components:Vue组件
创建组件有三种方式:
1. 通过创建vue文件
比如说,Demo.vue就是一个组件。
<template>
<div class="red">
我是demo组件
</div>
</template> //后边还有script及style标签
怎么在main.js里使用这个组件呢?
import Demo from "./Demo.vue"; // 先导入这个组件
new Vue({
components: { //在Vue实例里,通过components属性,
Anqi: Demo, //给组件一个名字,值是这个组件
},
data() {
return {
n: 0,
array: [1, 2, 3, 4, 5, 6, 7, 8],
};
},
template: `
<div class="red">
{{n}}
<button @click="add">+1</button>
<Anqi/> //在template里写这个组件名字
<hr>
{{filter()}}
</div>
`,
methods: {
.....
},
}).$mount("#app");
效果:
2. 用JS的形式创建组件
在main.js里:
Vue.component("demo2", { //注意没有s
template: `
<div>我是第二个组件</div>
`,
});
第一个参数是组件的名字,第二个参数是个对象,自己写template。(作为比较,上一种方法是在vue文件里写组件的template)
此时就不需要import了,直接在Vue实例的template里写:<demo2/>
所以实例和组件是差不多的,实例是直接new使用。组件是放到component里给它一个名字,让别人使用。(或者通过vue文件)
3. 上两种方法的组合
new Vue({
components: {
demo3: {
template: `<div>我是第三个组件</div>`,
},
},
data() {
.....
},
template: `
<div class="red">
{{n}}
<button @click="add">+1</button>
<demo3/>
<hr>
{{filter()}}
</div>
`,
methods: {
......
},
}).$mount("#app");
使用方法1的components属性,给组件一个名字,但是不使用导入的组件,自己写组件的内容。使用方法2的key:value的形式。
总结
推荐使用第一种方法,import组件的形式,因为模块化。
但是像上边那样写,给Demo起另外一个名字,很奇怪。直接Demo:Demo就好了。由ES6的新语法,属性名和属性值一样,可以直接写成:
import Demo from './Demo.js'
new Vue({
components:{Demo},
})
大小写问题:组件一般首字母大写Demo,文件名最好全小写
5. 四个钩子
created,mounted,updated,destroyed,它们都是函数,我们关注在什么时候会调用这个钩子。
created
在实例出现在内存中之后,被调用。此时实例还未出现在页面中。
怎么证明?在created函数里先写一句debugger,设一个断点
created(){
debugger
console.log('实例出现在内存里,没有出现在页面中')
}
刷新页面时,进入了断点,说明created函数被调用了。但是页面中并没有n和按钮,说明created被调用的时候,实例还没有出现在页面里。
mounted
实例出现在页面中之后,被调用。也就是已经挂载到页面了,用自己创建的el节点替换了页面的el。
mounted() {
debugger;
console.log("实例出现在页面");
},
同样,设一个断点验证。进入断点了,说明mounted被调用了。此时页面中有n和按钮,说明mounted被调用之前,实例就已经出现在页面里了。
updated
在实例更新之后,被调用。
updated() {
console.log("更新了");
console.log(this.n);
},
比如我们的+1按钮。不点击按钮时,不会调用updated。当点击按钮的时候,会把n+1,数据更新了。控制台打印了“更新了”,而且接下来打印的数值是+1之后的数值。所以是在已经把数据更新了,重新渲染到页面里了,才会触发这个函数。
destroyed
在实例消亡之后,被调用。
怎么实现让一个实例消亡呢?
把之前的vue实例变成另一个实例的组件,也就是说,让n和+1按钮一起成为一个组件。
<template>
<div class="red">
{{n}}
<button @click="add">+1</button>
</div>
</template>
<script>
export default {
data() {
return {
n: 0
};
},
created() {
console.log("实例出现在内存中,没有出现在页面里");
},
mounted() {
console.log("实例出现在页面");
},
updated() {
console.log("更新了");
console.log(this.n);
},
destroyed() {
console.log("实例消亡了");
},
methods: {
add() {
this.n += 1;
}
}
};
</script>
<style>
.red {
color: red;
}
</style>
以上就是Demo.vue文件。然后在main.js里import这个组件,new Vue()一个实例,使这个Demo成为这个实例的组件。
import Demo from "./Demo.vue";
new Vue({
data() {
return { visible: true };
},
components: { Demo },
template: `
<div>
<button @click='toggle'>toggle</button>
<hr>
<Demo v-if='visible===true'/>
</div>
`,
methods: {
toggle() {
this.visible = !this.visible;
},
},
}).$mount("#app");
这个实例里边还有一个toggle按钮,点击它,就会把visible取反。通过v-if,如果visible是true,就显示Demo组件;false,就隐藏。
当Demo组件从页面消失,就是消亡了。就会看到打印出“实例消亡了”
6. props:外部数据/属性
用于接收来自父组件的数据。
Demo.vue是一个实例的组件。
<template>
<div class="red">{{message}}</div>
</template>
<script>
export default {
props: ["message"]
};
</script>
Demo组件的html有一个message,但是他不是data,而是外部数据,需要外部给它传。怎么声明呢?在script里,props: ["message"]。表示我这个message是一个props数据,需要外部传进来。
在main.js的实例里:
import Demo from "./Demo.vue";
new Vue({
components: { Demo },
template: `
<div>
<Demo message='我是第一个props'/>
</div>
`,
}).$mount("#app");
怎么传:在Demo组件后边,以属性名=属性值的形式传
传入形式:可以传字符串,也可以传变量,也可以传函数
如:
new Vue({
data() {
return { n: 0 };
},
components: { Demo },
template: `
<div>
<Demo message='n'/>
</div>
`,
}).$mount("#app");
Vue实例有一个数据n,值是0.我想把n传给message。
如果写成
<Demo message='n'/> 传入的是字符串n,页面中出现n这个字母。
写<Demo :message='n'/> 传入的就是变量n的值,就是0.在message前边加 : ,意思是后边是JS代码,在JS里n就代表变量n。不管最外层的''
<Demo :message=" 'n' "/>等价于<Demo message='n'/>,都是字符串n
传函数:
<template>
<div class="red">
这里是Demo的内部
{{message}}
<button @click="fn">call fn</button>
</div>
</template>
<script>
export default {
props: ["message", "fn"]
};
</script>
Demo组件里有一句话,一个{{message}} , 还有个按钮。点击按钮会调用fn函数。其中message和fn都不是自己的,是在props里定义的,需要外部给传进来。
import Demo from "./Demo.vue";
new Vue({
data() {
return { n: 0 };
},
components: { Demo },
template: `
<div>
{{n}}
<Demo :message='n' :fn='add'/>
</div>
`,
methods: {
add() {
this.n += 1;
},
},
}).$mount("#app");
在实例里,自己有个{{n}},还有个Demo组件。传message是n的值,fn是add函数。实例自己没有按钮,需要点击组件的按钮,给自己的n加1.然后组件自己没有事件处理函数,是实例爸爸给它传的函数。这个函数会把实例自己的内部数据n 加1。同时组件身上的message传了爸爸的n,也会实时更新数据。