系列文章目录
文章目录
一、计算属性
函数编写在computed中后将被编入vue实例中,可以作为一个属性直接使用,计算属性只有在它的相关依赖发生改变时才会重新求值。
如果编写时使用箭头函数this不再指向vue实例,不过可以添加一个参数,该参数为vue实例
# 输入在input框中的字符串最后一个字母将变为大写的
<div id="app">
<p><input type="text" v-model="text1">输入:{{newText}}</p>
<p>通过箭头函数输入:{{newText1}}</p>
</div>
var vm = new Vue({
el:'#app',
data:{
text1:'',
},
computed:{
newText(){
# 此处由于是将最后一个字母大写,所以依赖不断的改变
let len = this.text1.length
return this.text1.substr(0, len-1) + this.text1.substr(len-1).toUpperCase()
},
newText1: v => {
let len = v.text1.length
return v.text1.substr(0, len-1) + v.text1.substr(len-1).toUpperCase()
}
},
})
二、侦听属性
一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。
var vm = new Vue({
el:'#app',
data:{
text1:'',
ll:{
kk:{
ff:'ff'
}
}
},
watch:{
// 该方法侦听text1是否被改变
text1(val, oldval){
console.log('text1被改变了,原来的值%s,新值%s',oldval, val)
},
// 该方法侦听ll是否被改变
ll(val, oldval){
console.log('ll被改变了,原来的值%s,新值%s',oldval, val)
},
// 该方法侦听ll中嵌套的kk是否被改变,可以不断向内获取
'll.kk'(val, oldval){
console.log('kk被改变了,原来的值%s,新值%s',oldval, val)
},
}
})
三、组件
扩展 HTML 元素,封装可重用的代码,目的是复用,每个组件都有自己的html、css、js
1.组件的建立
组件创建可以有自己的template、data、methods、match等
需要注意的是:
1.自定义组件名称必须按照大驼峰命名或者使用至少一个-来连接,使用大驼峰命名在 DOM中会失效,所以推荐使用-的形式。如:ShowComponent或者show-component
2.template中必须只有一个根标签,书写template时使用反引号(推荐)或者字符串自由拼接dom(不推荐)
3.data不再和vue对象一样了,无论data中是否只有一个变量都需要编写为函数
4.组件中不可以使用components来进行组件局部注册,这样会产生组件循环嵌套,导致vue找不到组件
var componentA = { //componentA 自行定义名字
template: `
<div>
<p>组件</p>
<p><button @click="showbtn">点击显示文字</button></p>
<p v-if="key">{{text}}</p>
</div>
`,
// data是组件的数据,与别的组件互不影响
data() {
return {
text:'文字1',
key:false,
}
},
// methods是组件的事件,与别的组件互不影响
methods:{
showbtn(){
this.key = !this.key
}
},
}
2.组件注册
组件标签名是自定的组件名
1.组件全局注册
// 直接绑定在全局的组件写法
Vue.component('all-com', { //'all-com'为全局组件的标签名
// 此处template是全局组件的样式
template:`
<div>
<p>全局组件</p>
<p><button @click="showbtn">点击显示文字</button></p>
<p v-if="key">{{text}}</p>
</div>
`,
// data是全局组件的数据,与别的组件互不影响
data() {
return {
text:'文字1',
key:false,
}
},
// methods是全局组件的事件,与别的组件互不影响
methods:{
showbtn(){
this.key = !this.key
}
},
})
2.组件局部注册
局部注册可以在components中使用对象的形式注册或者直接编写
new Vue({
el:'#app',
data:{
},
components: {
'self-coms': componentA, // 对象形式注册 'self-coms'为局部组件的标签名
'component-code':{ //编写仅在该vue中使用的组件 'component-code'为局部组件的标签名
template: `
<div>
<p>自定义组件1</p>
</div>
`,
}
}
})
四、组件通信
1.组件通信父传子(自定义属性)
父vue或者组件给子组件传递数据是需要使用到props的
props是单向数据流,使用props传递到子组件的数据实际上是引用型,也就是说子组件如果修改该传递过来的属性会影响到父的数据状态,所以子组件获得的属性一般不做数据修改。
1.首先在父vue中确保需要传递的数据存在,并且子组件已经注册为父vue的局部组件
new Vue({
el:'#app',
data:{
text1:'根vue的data1', // 需要传递的数据1
number1:11111, // 需要传递的数据2
},
components: {
'self-coms': componentA, // 子组件为该vue的局部组件
}
})
2.在对应的子组件标签处绑定上对应数据
针对于绑定自定义属性给子组件
例如下方代码中:data1
其中:表示为动态绑定,动态绑定可以赋值变量、字符串、数据、对象等,不使用:为静态绑定,只能传递固定的字符串、数组、对象等
data1是自订的,该名字为子组件接收到的数据的名称
<all-com :data1="text1" :data2="number1" @get-data="faGetData"></all-com>
3.父vue传过来的数据的使用
父vue传递过来的数据可以直接使用也可以储存下来作为子组件自己的数据,注意储存下来的数据为引用型,修改该存储数据会改变父vue的数据,所以一般不会进行修改。
使用之前需要在props中绑定数据,绑定的数据名称为之前子组件上设置的自定义属性名
绑定完之后可以直接插值语法使用,也可以将该值赋给data中自己设置的变量
// 直接绑定在全局的组件写法
Vue.component('all-com', {
// 此处template是全局组件的样式
template:`
<div>
<p>全局组件</p>
<p><button @click="showbtn">点击显示文字</button></p>
<p>父传子获取后直接使用{{data1}}</p>
<p>父传子获取后储存下来作为本地数据使用{{text1}}</p>
</div>
`,
// data是全局组件的数据,与别的组件互不影响
data() {
return {
text:'文字1',
text1: this.data1,
}
},
// methods是全局组件的事件,与别的组件互不影响
methods:{
showbtn(){
this.key = !this.key
},
},
props:['data1','data2'], // 只需要获取父传过来的数据使用数组
})
2.组件通信父传子props数据检验
检验父vue或者组件传递给子组件的数据主要在props中进行,获取父传过来的数据同时验证其类型,数据类型不对时会在控制台警告,警告只是一个提示
props:['data1','data2'], // 只需要获取父传过来的数据使用数组
props:{
'data1':String, //验证传来的数据必须为string
'data2':[Number,String]//验证传来的数据可以为多种时用数组
},
3.组件通信子传父(自定义事件)
子组件传递数据给父vue或者组件是需要设置自定义函数来进行的
1.子组件中设置对应的事件
设置传递数据事件时可以使用任意触发形式,函数体为:
this.$emit('get-data', this.text2) 其中第一个参数为父类绑定事件的名字,后续可以添加n个参数,参数会依次作为变量传递到设定的事件中
// 直接绑定在全局的组件写法
Vue.component('all-com', {
// 此处template是全局组件的样式
template:`
<div>
<p>全局组件</p>
<p><button @click="clickbtn">发送数据给父</button></p>
</div>
`,
// data是全局组件的数据,与别的组件互不影响
data() {
return {
text2:'子的数据'
}
},
// methods是全局组件的事件,与别的组件互不影响
methods:{
// 子传父数据
clickbtn(){
this.$emit('get-data', this.text2)
},
},
})
2.为传递数据的子组件设置自定义函数
// 此处的@get-data是之前在this.$emit设置的第一个参数,自定义事件的值为父vue获取数据的事件
<all-com @get-data="faGetData"></all-com>
3.父组件设置获取数据的事件
new Vue({
el:'#app',
data:{
son_data:'',
},
methods:{
'faGetData'(data1){ # 在此处按照之前设置的父vue获取数据的事件名来设置事件
this.son_data = data1
}
},
components: {
'self-coms': componentA,
}
})
五、ref属性
ref放在普通标签上,拿到的是原生节点,原生节点操作时只能使用js原生DOM语法来实现
ref放在组件上,拿到的是组件对象,组件对象可以获取其中变量、可以父传子或者子传父
1.通过ref获取普通标签
<div id="app">
<button @click="clickbtn">点击查看ref</button>
<p ref="pele"></p>
</div>
new Vue({
el:'#app',
data:{
},
components: {
'self-coms': componentA,
},
methods:{
clickbtn(){
this.$refs['pele'].innerText='pppppppppp'
}
}
2.通过ref实现子传父
<div id="app">
<button @click="clickbtn">点击查看ref</button>
<all-com ref="allele"></all-com>
</div>
父vue代码
new Vue({
el:'#app',
data:{
},
components: {
'self-coms': componentA,
},
methods:{
clickbtn(){
this.$refs.allele.getData()
this.$refs['allele'].getData()
}
}
})
子组件代码
// 直接绑定在全局的组件写法
Vue.component('all-com', {
// 此处template是全局组件的样式
template:`
<div>
<p>全局组件</p>
</div>
`,
// data是全局组件的数据,与别的组件互不影响
data() {
return {
text:'文字1',
}
},
// methods是全局组件的事件,与别的组件互不影响
methods:{
getData(){
console.log(this.text)
}
},
})
3.通过ref实现父传子
<div id="app">
<button @click="clickbtn">点击查看ref</button>
<all-com ref="allele"></all-com>
</div>
父vue代码
new Vue({
el:'#app',
data:{
},
components: {
'self-coms': componentA,
},
methods:{
clickbtn(){
this.$refs.allele.setData('父传给子的值')
this.$refs['allele'].setData('父传给子的值')
}
}
})
子组件代码
// 直接绑定在全局的组件写法
Vue.component('all-com', {
// 此处template是全局组件的样式
template:`
<div>
<p>全局组件</p>
</div>
`,
// data是全局组件的数据,与别的组件互不影响
data() {
return {
text:'文字1',
}
},
// methods是全局组件的事件,与别的组件互不影响
methods:{
setData(data){
console.log(data)
},
},
})
六、数据总线
不同层级的不同组件通信,不再局限于父子之间通信
1.创建一个数据总线
var datas = new Vue()
2.在需要接收数据的组件或者vue设置mounted
mounted(){
datas.$on('wait', (data1)=>{
this.text = data1
})
},
3.在发送数据的组件或者vue设置mounted
mounted(){
datas.$emit('wait', this.text)
},
七、动态组件
通过component配合is属性,决定显示的组件是哪个,达成动态显示我们需要的组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<ul>
<li><button @click="comName='one'">组件1</button></li>
<li><button @click="comName='two'">组件2</button></li>
<li><button @click="comName='three'">组件3</button></li>
</ul>
<component :is="comName">
</component>
</div>
</body>
<script>
Vue.component('one', {
template:`
<div>
<p>全局组件1</p>
</div>
`,
data() {
return {
}
},
})
Vue.component('two', {
template:`
<div>
<p>全局组件2</p>
</div>
`,
data() {
return {
}
},
})
Vue.component('three', {
template:`
<div>
<p>全局组件3</p>
</div>
`,
data() {
return {
}
},
})
new Vue({
el:'#app',
data:{
comName:'one'
},
})
</script>
</html>
keep-alive标签可以保存之前组件输入的内容,本质是在切换别的组件时不销毁之前的组件
<keep-alive>
<component :is="comName">
</component>
</keep-alive>
八、插槽
1.匿名插槽
每个组件或者vue只能存在一个匿名插槽,插槽中的内容可以是标签、组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<all-com>
<slot><all-com1></all-com1></slot> # 在对应需要插入的地方设置,然后去组建中设置
</all-com>
</div>
</body>
<script>
// 直接绑定在全局的组件写法
Vue.component('all-com', {
// 此处template是全局组件的样式
template:`
<div>
<p>全局组件</p>
<p>{{text}}</p>
<slot></slot>
<p>{{text1}}</p>
</div>
`,
// data是全局组件的数据,与别的组件互不影响
data() {
return {
text:'原有文字1',
text1:'原有文字2'
}
},
})
// 直接绑定在全局的组件写法
Vue.component('all-com1', {
// 此处template是全局组件的样式
template:`
<div>
<p>全局组件1</p>
<p>{{text}}</p>
<p>{{text1}}</p>
</div>
`,
// data是全局组件的数据,与别的组件互不影响
data() {
return {
text:'新原有文字1',
text1:'新原有文字2'
}
},
})
new Vue({
el:'#app',
data:{
},
})
</script>
</html>
2.具名插槽
可以通过给slot设置name属性来制作多个插槽
显示区域使用v-slot:名称 来设置,名称需要对应上插槽内容的name
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<all-com>
<slot v-slot:three></slot>
<slot v-slot:two></slot>
<slot v-slot:one></slot>
</all-com>
</div>
</body>
<script>
// 直接绑定在全局的组件写法
Vue.component('all-com', {
// 此处template是全局组件的样式
template:`
<div>
<p>全局组件</p>
<p>{{text}}</p>
<p>打乱顺序反过来插入</p>
<slot name="one"><p>这里是第二个插槽之前</p></slot>
<slot name="two"><all-com1></all-com1></slot>
<slot name="three"><p>这里是第二个插槽之后</p></slot>
<p>{{text1}}</p>
</div>
`,
// data是全局组件的数据,与别的组件互不影响
data() {
return {
text:'原有文字1',
text1:'原有文字2'
}
},
})
// 直接绑定在全局的组件写法
Vue.component('all-com1', {
// 此处template是全局组件的样式
template:`
<div>
<p>全局组件1</p>
<p>{{text}}</p>
<p>{{text1}}</p>
</div>
`,
// data是全局组件的数据,与别的组件互不影响
data() {
return {
text:'新原有文字1',
text1:'新原有文字2'
}
},
})
new Vue({
el:'#app',
data:{
},
})
</script>
</html>
3.作用域插槽
作用域插槽是带数据的插槽,子组件提供给父组件的参数
1.在子组件中设置
<slot v-bind:text="text"></slot> v-bind:在父组件中使用的变量名="子组件中的变量名"
2.在需要使用子组件变量的地方为子组件标签绑定v-slot:default属性
<all-com v-slot:default="slotProps"> "slotProps"可以自己随意取名
<slot v-slot:three></slot>
<slot v-slot:two></slot>
<slot v-slot:one></slot>
偷过来的{{slotProps.text}}
</all-com>
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<all-com v-slot:default="slotProps">
<slot v-slot:three></slot>
<slot v-slot:two></slot>
<slot v-slot:one></slot>
偷过来的{{slotProps.text}}
</all-com>
</div>
</body>
<script>
// 直接绑定在全局的组件写法
Vue.component('all-com', {
// 此处template是全局组件的样式
template:`
<div>
<p>全局组件</p>
<p>{{text}}</p>
<p>打乱顺序反过来插入</p>
<slot name="one" v-bind:text="text"><p>这里是第二个插槽之前</p></slot>
<slot name="two"><all-com1></all-com1></slot>
<slot name="three"><p>这里是第二个插槽之后</p></slot>
<slot v-bind:text="text"></slot>
<p>{{text1}}</p>
</div>
`,
// data是全局组件的数据,与别的组件互不影响
data() {
return {
text:'原有文字1',
text1:'原有文字2'
}
},
})
// 直接绑定在全局的组件写法
Vue.component('all-com1', {
// 此处template是全局组件的样式
template:`
<div>
<p>全局组件1</p>
<p>{{text}}</p>
<p>{{text1}}</p>
</div>
`,
// data是全局组件的数据,与别的组件互不影响
data() {
return {
text:'新原有文字1',
text1:'新原有文字2'
}
},
})
new Vue({
el:'#app',
data:{
},
})
</script>
</html>