前端小白的碎碎念:好难好难好难。。。。。,还需要多看
一、Vue中的options
const vm = new Vue(options)
options的五类属性:
1)数据:data、 props、 propsData、 computed、methods、 Watch
2)DOM: el、 template、 render、 renderError
3)生命周期钩子: beforeCreate、 created、beforeMount、 mounted、 beforeUpdate、 updated、 activated、 deactivated、 beforeDestroy、 destroyed、errorCaptured
4)资源: directives、 filters、 components
5)组合: parent, mixins、 extends、 provide、 inject
二、注册组件
01.全局注册(Vue.component)
全局注册:可以在全局任意地方访问
<body>
<div id="app"></div>
<script>
//注册组件
//1.全局---->可以在全局任意地方访问
const Foo = {
template: `<div>foo</div>`
}
//第一个字段:标记当前要注册的组件的名称
//第二个字段:放置一个视图,可以先提前声明
Vue.component("Foo", Foo); //全局注册
const app = new Vue({
el: "#app",
data: {
msg: "你好"
},
template: `
<div>root app
<Foo></Foo> // <div>foo</div>
</div>
`
})
</script>
</body>
02.局部注册(components)
存在作用域问题
const Bar = {
template: `<div>Bar</div>`
}
const Foo = {
//局部注册:Bar只能在 Foo 内部访问
components: {
Bar, //Bar为简写形式,或者"Bar":Bar (key:value形式)
},
template: `<div>foo
<Bar></Bar>
</div>
`
}
!!!注意事项
1)data(){ }
通过一个函数返回一个对象,确保组件之间相互独立
因为如果采用Object(data:{count:1}),则相当于创建的时候采用同一个对象,当在某一个组件更改则其余的也会受到影响
const Foo = {
//局部注册:Bar只能在 Foo 内部访问
components: {
Bar,
},
//如果在组件内给一个data,这里data必须是一个函数
data() {
return {
count: 1,
};
},
template: `<div>foo
{{count}}
<Bar></Bar>
</div>`
}
2)只能有一个 root 根节点
const Foo = {
......
//template必须用一个<div></div>包裹,但是在vue3,此语法不再强制
template: `<div>foo
{{count}}
<Bar></Bar>
</div>
`
}
三、Vue的生命周期
- 快捷插件(Vue VsCode Snippets):可以根据几个字母,自动的创建代码
- 生命周期:创建->挂载->更新->销毁
const Foo = {
data() {
return {
count: 1,
};
},
//==========创建==========
beforeCreate() {
console.log("before-create");
},
created(){
//page -> fetch -> data
//在create中拉取数据较好,因为此时视图还未渲染
console.log("created");
},
//==========挂载==========
beforeMount(){
console.log("before-mounted");
},
mounted(){
//整个视图创建完成
console.log("mounted");
},
//==========更新==========
beforeUpdated(){
console.log("before-update");
},
updated(){
console.log("updated");
},
//==========销毁==========
beforeDestroy(){
console.log("beofre-destroy");
},
Destroy(){
cosnole.log("destroy");
},
template: `<div>foo
</div>`
}
3. 多个组件调用的顺序
//子组件
const Bar = {
data() {
return {
};
},
//创建
beforeCreate() {
console.log("bar-before-create");
},
created() {
console.log("bar-created");
},
//挂载
beforeMount() {
console.log("bar-before-mounted");
},
mounted() {
//整个视图创建完成
console.log("bar-mounted");
},
//更新
beforeUpdated() {
console.log("bar-before-update");
},
updated() {
console.log("bar-updated");
},
//销毁
beforeDestroy() {
console.log("bar-beofre-destroy");
},
Destroy() {
cosnole.log("bar-destroy");
},
template: `<div>foo
{{count}}
<button @click="count++">click</button>
</div>`
}
//父组件
const Foo = {
component: {
Bar,
},
data() {
return {
count: 1,
};
},
//创建
beforeCreate() {
console.log("before-create");
},
created() {
//请求后端的数据
console.log("created");
},
//挂载
beforeMount() {
console.log("before-mounted");
},
mounted() {
//所有的子组件已经创建完成
//整个视图创建完成
//此过程常用于事件的监听等
console.log("mounted");
},
//更新
beforeUpdated() {
console.log("before-update");
},
updated() {
console.log("updated");
},
//销毁
beforeDestroy() {
console.log("beofre-destroy");
},
Destroy() {
cosnole.log("destroy");
},
template: `<div>foo
{{count}}
<Bar></Bar>
<button @click="count++">click</button>
</div>`
}
### before-create ---> create ---> before-mount ---> bar-before-create --->bar-create --->bar-before-mount ---> bar-mount ---> mount
### 先创建父组件,在父组件挂载之前,完成子组件的初始化(创建+挂载),最后再加载父组件
四、props(声明一个组件可以接收到的参数)
const Foo = {
//声明一个组件可以接收到的参数
// props:["msg"];
//当有多个属性需要设置时,采用对象形式
//props:只读,不可写
props: {
//声明的msg也是一个响应式数据
msg: {
type: String,
defalut: "msgmsgmsg", //给定默认值
//自定义校验器,验证val 是否符合校验规则
validator(val) {
console.log(val);
return val === 'abc';
}
},
},
data() {
return {
count: 1,
};
},
template: `<div>foo
{{msg}}
</div>`
}
Vue.component("Foo", Foo);
const app = new Vue({
el: "#app",
data: {
msg: "你好"
},
//父组件和子组件之间的通信方式
template: `
<div>root app
//父组件传递给子组件
<Foo msg="abc"></Foo> //在validator中验证值
</div>
`
})
五、自定义事件
01.this.$emit
const Foo = {
data() {
return {
count: 1,
};
},
methods: {
handleClick() {
console.log("click");
//让 父级 接收到 子级传递来的消息
//子组件向父组件传值:this.$emit("function",param)
//第一个参数是函数的名字,param:需要传递的参数,可为多个
this.$emit("heihei", "a", "b");
}
},
template: `<div>foo
<button @click="handleClick">点击</button>
</div>`
}
Vue.component("Foo", Foo);
const app = new Vue({
el: "#app",
data: {
msg: "你好"
},
methods: {
//val secondVal 对应 emit 传递来的参数
handleHeiHei(val, secondVal) {
console.log(val);
console.log(secondVal);
console.log("heihei in parent component");
}
},
template: `
<div>root app
在父组件中 子组件引用处添加函数:v-on:function="function1";
//其中 function为子组件中定义函数 ( heihei事件名就是emit 发出的事件名称 ) ,function1为父组件定义函数--用于接收子组件传值并进行相应数据处理,可定义为同一名称
<Foo @heihei="handleHeiHei"></Foo>
</div>
`
})
02.v-model
写法一:
const Foo = {
//props 必须为["value"]
props: ["value"],
data() {
return {
count: 1,
};
},
methods: {
handleClose() {
//2.emit 为 input
this.$emit("input",false);
}
},
template: `<div v-if="value">foo
<button @click="handleClose">关闭</button>
</div>`
}
Vue.component("Foo", Foo);
const app = new Vue({
el: "#app",
data: {
msg: "你好",
showFoo: true
},
methods: {
handleClose(val) {
this.showFoo = val;
}
},
template: `
<div>root app
//3.$emit处采用input , 此处采用v-model
<Foo v-model="showFoo"></Foo>
</div>
`
})
六、插槽
将内容渲染进组件内,实现组件的通信
- 插槽简单实现
const Foo = {
data() {
return {
count: 1,
};
},
template: `<div>
<div>
默认slot
<slot></slot> //如果没加name,默认default
</div>
<div>
first
<slot name="first"></slot> //通过name指定slot
</div>
<div>
second
<slot name="second"></slot>
</div>
</div>`
}
Vue.component("Foo", Foo);
const app = new Vue({
el: "#app",
data: {
msg: "你好"
},
//Foo 如果什么都不写,采用默认slot中的内容,如果Foo中内容更改,则变成更改后的内容
// v-slot:first 缩写 #first
//通过v-slot将指定内容插入指定的slot内
template: `
<div>root app
<Foo>
012
<template v-slot:first>
345
</template>
<template #second>
678
</template>
</Foo>
</div>
`
})
- 插槽传递数据
const Foo = {
data() {
return {
count: 1,
title: "FooFooFoo"
};
},
template: `<div>
<slot name="first" :title="title" age="13"></slot>
</div> `
}
Vue.component("Foo", Foo);
const app = new Vue({
el: "#app",
data: {
msg: "你好"
},
template: `
<div>root app
<Foo>
<template #first="data">
{{data}} //结果:{ "title": "FooFooFoo", "age": "13" }
</template>
<template #first="{age}"> //想得到谁,则结构成对象的形式
{{age}}
</template>
</Foo>
</div>
`
})
七、组件的复用性
01.mixin(公用的方式用mixin抽离)
//mixin 将公共的部分抽离封装,写法和组件类似,options中相同的部分会合并
//鼠标移动的逻辑 x y
const MousemoveMixin = {
data() {
return {
x: 0,
y: 0
}
},
methods: {
handleMousemove(e) {
this.x = e.pageX;
this.y = e.pageY;
}
},
mounted() {
window.addEventListener("mousemove", this.handleMousemove);
},
destroyed() {
window.removeEventListener("mousemove", this.handleMousemove);
},
}
const Foo = {
mixins: [MousemoveMixin],
data() {
return {
count: 1
};
},
template: `<div>foo
{{x}}---{{y}}
</div>`
}
Vue.component("Foo", Foo);
const app = new Vue({
el: "#app",
data: {
msg: "你好"
},
template: `
<div>root app
<Foo></Foo>
</div>
`
})
!!!注意:mixin 缺点----->vue3中能解决
1)来源不清晰
2)命名冲突问题