组件作用就是把一个复杂的界面拆成一块一块,然后组合起来
全局组件
- 组件具有复用性,定义了就可以随便在哪里用
- 弊端就是定义了就会占资源
<script>
// 创建全局组件app
// 将website,describe,count都放入根组件中
const app = Vue.createApp({
template: `
<website />
<describe />
<count />
<count />
<count />
`
})
// 创建一个子组件 website
app.component('website',{
template: `
<h2>
fujingjie
</h2>
`
})
// 创建一个子组件 describe
app.component('describe',{
template: `
<h2>
henshuai
</h2>
`
})
// 创建一个子组件count
app.component('count', {
data(){
return{
count: 0
}
},
template: `
<div>
{{count}}
<button @click="count++">
增加1
</button>
</div>
`
})
const vm = app.mount("#app")
</script>
局部组件
- 局部组件定义就是类型声明一个变量
- 局部组件需要注册到app中,用components
- 局部组件命名用大驼峰命名法,FuJingJie这样的
<script>
// 定义局部组件
const Counter = {
data() {
return {
count: 0
}
},
template: `<div>{{count}}<button @click="count++">增加1</button></div>`
}
// 定义局部组件
const XieDaJiao = {
template: `<h2>xxxxx</h2>`
}
const app = Vue.createApp({
// 注册局部组件
components: {
jspang: Counter,
XieDaJiao
},
template: `
<h2>JSPang.com</h2>
<XieDaJiao />
<jspang />
`
})
const vm = app.mount("#app")
</script>
父子组件的传值
- 静态传值,也就是写死的。传的值都是string,写123,出来的也是string
const app = Vue.createApp({
template:`
<h2>JSPang.com</h2>
<Son name=123 />
`
})
app.component('Son',{
props:['name'],
template:`<div>{{name}} div </div>`
})
- props 用来接收变量的
- 动态参数传值,就是把动态参数放到data中
const app = Vue.createApp({
data(){
return {
name: "技小胖"
}
},
template:`
<h2>JSPang.com</h2>
// 动态参数绑定用v-bind
<Son v-bind:name="name" />
`
})
- 传递的的参数为函数
- 箭头函数,类似于python里的lambda,参考https://www.runoob.com/js/js-function-definition.html
// 定义一个子组件,需要参数pay
app.component('XiaoJieJie',{
props:['pay'],
methods:{
handleClick(){
alert('请付钱....')
this.pay() // 付多少钱,是顾客说的算的,所以调用时才能确定
}
},
template:`<div @click="this.handleClick"> 和小姐姐,打招呼! </div>`
})
const app = Vue.createApp({
data(){
return {
name:123,
// 箭头函数
pay:()=>{
alert('给你500元')
}
}
},
template:`
<h2>JSPang.com</h2>
<Son :name="name" />
<xiao-jie-jie :pay="pay"/>
`
}
参数校验
- 类型校验
- required 必填项
- default 默认值
- 精准校验 validator
- search 方法,找到了返回位置,没找到返回-1
<script>
const app = Vue.createApp({
data() {
return {
name: 'qwer',
}
},
template: `
<Son :name="name" />
<Son />
`
})
app.component('Son',{
props:{
name: {
type: String,
default: 'axtat',
required: true,
validator: function(value) {
console.log(value.search("x"))
return value.search("x") != -1
}
}
},
template:`<div>{{ typeof name}} </div>`
})
const vm = app.mount("#app")
</script>
单向数据流机制
- 数据从父级组件传递给子组件,只能单向绑定。子组件内部不能直接修改从父组件传递过来的数据。
- 目的是防止数据在复用时,造成重复。就是改了一个,另一个也变了。
- 要修改父组件传过来的参数,就要在组件内的数据项中声明一个变量,把父组件传递过来的变量赋值给内部变量,然后就可以随意修改了
<script>
const app = Vue.createApp({
data() {
return {
counter: 0
}
},
template: `
<h2>JSPang.com</h2>
<counter :counter="counter"/>
`
})
app.component('Counter', {
props: ['counter'],
data(){
return {
newCounter: this.counter
}
},
template: `
{{newCounter}}<button @click="this.newCounter+=1">增加数量</button>
`
})
const vm = app.mount("#app")
</script>
Non-props
- 子组件中没有写props的时候。也是可以把参数传递到子组件中的。不要的话,可以在子组件中写一个props来接受参数,但是不用就好。
const app = Vue.createApp({
template: `
<h2>JSPang.com</h2>
<hello msg="jspang" />
`
})
app.component('Hello', {
props: ['msg'],
template: `<h3>Hello World</h3>`
})
- 父组件上写的style,也是会完全传递到子组件上的
const app = Vue.createApp({
template: `
<h2>JSPang.com</h2>
<hello style="color:red;" />
`
})
- inheritAttrs 用了之后就不会接受任何参数了
app.component('Hello', {
inheritAttrs: false,
template: `<h3>Hello World</h3>`
})
- Non-props在多节点的时候会失效,用attrs来解决
<script>
const app = Vue.createApp({
template: `
<h2>JSPang.com</h2>
<hello style="color:red;" msg="jspang" />
`
})
app.component('Hello', {
template: `
<h3 v-bind="$attrs">Hello World</h3>
<h3 :style="$attrs.style" >Hello World</h3>
`
})
const vm = app.mount("#app")
</script>
- 在业务逻辑中也是可以用Non-props属性,比如在生命周期中就可以用attrs
app.component('Hello', {
mounted() {
console.log(this.$attrs.msg)
},
template: `
<h3 v-bind="$attrs">Hello World</h3>
<h3 v-bind:style="$attrs.style">Hello World</h3>
<h3>Hello World</h3>
`
})
组件之间通过事件进行通信
- 子组件中如果想改变父组件中的值,就需要调用父组件的事件.父组件中要添加响应事件
<counter :counter="counter" @add="handleAddCounter"/>
- 用emits来调用父组件中的事件
emits: ['add'],
- param 父组件可以接受子组件中的参数
- 子组件中可以增加对值得校验
<script>
const app = Vue.createApp({
data() {
return {
counter: 0
}
},
// param 来接受子组件的参数
methods: {
handleAddCounter(param) {
console.log(param)
this.counter = param
}
},
// counter中增加add事件
template: `
<h2>JSPang.com</h2>
<counter :counter="counter" @add="handleAddCounter"/>
`
})
// emits调用父组件中的add参数
app.component('Counter', {
props: ['counter'],
// emits: ['add'],
// 对值进行校验,大于20就告警
emits: {
add: (value) => {
return value < 20 ? true : false
}
},
methods: {
handleClick() {
this.$emit('add', this.counter + 3)
},
},
template: `
{{counter}}<button @click="handleClick">增加数量</button>
`
})
const vm = app.mount("#app")
</script>
插槽slot
- 在子组件中加入slot,在父组件中使用双标签进行调用
- 插槽中可以使用子组件
- 插槽中可以使用动态数据
- 父模板里调用的数据属性,使用的都是父模板里的数据
- 子模板里调用的数据属性,使用的都是子模板里的数据
<script>
const app = Vue.createApp({
data() {
return {
jishi: '晓红'
}
},
template: `
<h2>欢迎光临红浪漫-请选择您的技师</h2>
<ji-shi >
<div style="color:red;font-size:50px;">{{jishi}}, <project /></div>
</ji-shi>
<ji-shi > <div style="color:green;font-size:50px;">刘英</div> </ji-shi>
`
})
app.component('JiShi', {
data() {
return {
jishi: '谢大脚'
}
},
template: `
<div>
<span>经过你的慎重考虑.最终选择了。</span>
<span>
<slot> </slot>
</span>
</div>
`
})
app.component('project', {
template: `<span style="color:blue;">项目是胖哥老三样</span>`
})
const vm = app.mount("#app")
</script>
- 插槽可以添加默认值
- 可以命名,使用就是
v-solt:name
也可以用简写#name
const app = Vue.createApp({
template: `
<h2>欢迎光临红浪漫-请选择您的技师</h2>
<ji-shi></ji-shi>
<hong-lang-man>
<template v-slot:one><div>1.女宾一位,请上三楼。</div></template> // 指定name是one的slot
<template #two><div>3.顾客选择了全身SPA。</div></template>
</hong-lang-man>
`
})
app.component('JiShi',{
template:`
<div>
你选择了
<slot>
<span style="color:green;">晓红</span> // 默认值
</slot>
为你服务。
</div>
`
})
app.component('HongLangMan',{
template:`
<div>
<slot name="one"></slot> // 取名为one
<div>2.你选择了大脚为你服务</div>
<slot name="two"></slot>
</div>
`
})
const vm = app.mount("#app")
- 作用域插槽
- 子组件中有插槽,也有变量,这些变量如何在父组件中进行使用。作用域插槽就是解决这个问题的。
- 子组件中的信息类型要父组件使用时才能确定,就需要用到作用域插槽,比如标签之类的
- 父组件中用子组件中的值要用v-bind,确定之后父组件中就可以用
v-slot="xxx"
的形式接受。 - props中传递的数据都是对象,要加item。
{{props.item}}
- 简写可以直接
v-slot="{item}"
<script>
const app = Vue.createApp({
template: `
<h2>欢迎光临红浪漫-请选择您的技师</h2>
<list v-slot="props">
<span>{{props.item}}-{{props}}</span>
</list>
`
// 简写
// <list v-slot="{item}">
// <div>{{item}}</div>
// </list>
})
app.component('List', {
data() {
return {
list: ['大脚', '刘英', '晓红']
}
},
template: `
<div>
<slot v-for="item in list" :item="item">
</div>
`
})
const vm = app.mount("#app")
- 动态组件和状态保存
<component :is="xxxx" />
这样就表示使用动态组件<keep-alive>
可以启动缓存,保存信息
<script>
const app = Vue.createApp({
data(){
return {showItem:'dajiao'}
},
methods:{
handleClick(){
this.showItem= this.showItem=='dajiao'?'liuying':'dajiao'
}
},
template: `
<h2>欢迎光临红浪漫-请选择您的技师</h2>
<keep-alive>
<component :is="showItem" />
</keep-alive>
<button @click="handleClick">切换佳丽</button>
`
})
app.component('dajiao',{
template:`
<input />
`
})
app.component('liuying',{
template:`<img src="https://newimg.jspang.com/liuying01.jpg" />`
})
const vm = app.mount("#app")
</script>
promise
- Promise 构造函数只有一个参数,是一个函数,这个函数在构造之后会直接被异步运行,所以我们称之为起始函数。起始函数包含两个参数 resolve 和 reject。
- 调用 resolve 代表一切正常,reject 是出现异常时所调用的
- Promise 类有 .then() .catch() 和 .finally() 三个方法,这三个方法的参数都是一个函数
- .then() 可以将参数中的函数添加到当前 Promise 的正常执行序列
- .catch() 则是设定 Promise 的异常处理序列,
- .finally() 是在 Promise 执行的最后一定会执行的序列。
- .then() 传入的函数会按顺序依次执行,有任何异常都会直接跳到 catch 序列
异步组件
- 就是要等到相应的条件触发的时候,才会执行,比如等了10秒再执行,这种就是异步组件
- defineAsyncComponent() 声明一个异步组件
<script>
const app = Vue.createApp({
template: ` <div><tongbu /></div>`
})
app.component('tongbu',{
template:`<div>JSPang.com</div>
<async-component />
`
})
app.component('async-component',Vue.defineAsyncComponent(()=>{
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve({
template:`<div>这是一个异步组件</div>`
})
},3000)
})
}))
const vm = app.mount("#app")
</script>
provider和inject多级传值
- 组件之间有很多层级关系的时候,要传递参数,用props不方便,可以用provider和inject
- 在最高层中提供了newHouse,在child-child中可以直接用inject接收
<script>
const app = Vue.createApp({
data(){
return {house:'北京别墅一套'}
},
provide:{
newHouse:'北京200平方房子一套'
},
template: `
<div>我有一套房子,我先传给我的儿子</div>
<child :house="house" />
`
})
app.component('child',{
props:['house'],
template:`
<div>我是子组件,我要把房子再传给我儿子。</div>
<div>儿子接收{{house}}</div>
<child-child :house="house" />
`
})
app.component('child-child',{
props:['house'],
inject: ['newHouse'],
template:`
<div>我是孙子,等待接收房子</div>
<div>孙子接收{{house}}, {{newHouse}}</div>
`
})
const vm = app.mount("#app")
</script>