vue 计算和监听属性+组件通信+动态组件+插槽
目录
计算属性和监听属性
计算属性
在computed对象中写函数,这个函数可以当作属性使用。
并且该属性仅在它的相关依赖发生改变时才会重新求值,即该函数在相关依赖不被改变时是不会执行的。
<!-- 写在插值语法内-->
<input type="text" v-model="myText"> ------------>{{myText.substr(0,1).toUpperCase()+myText.substr(1)}}
<br>
<!-- 写在methods中-->
<input type="text" v-model="myText2"> ------------>{{getText()}}
<br>
<!-- 写在computed中-->
<input type="text" v-model="myText3"> ------------>{{getName}}
</div>
<script>
new Vue({
el:'#app',
data:{
myText:'',
myText2:'',
myText3:''
},
methods:{
// 页面每次发生改变都会执行一次
getText() {
console.log('getText')
return this.myText2.substr(0,1).toUpperCase()+this.myText2.substr(1)
}
},
computed:{
// 只有myText3发生改变时才会执行
getName(){
console.log('getName')
return this.myText3.substr(0,1).toUpperCase()+this.myText3.substr(1)
}
}
})
</script>
重写过滤案例
<div id="app">
<h1>过滤</h1>
<input type="text" v-model="myText">
<hr>
<p v-for="item in newList">{{item}}</p>
</div>
<script>
new Vue({
el:'#app',
data:{
myText:'',
dataList: ['a', 'at', 'atom', 'be', 'beyond', 'cs', 'csrf'],
},
computed:{
newList(){
// filter()把传入的函数作用于每一个元素,然后根据返回值是true和false决定保留还是丢掉该元素。
// indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。如果没有找到匹配的字符串则返回 -1。
return this.dataList.filter(item=>{
return item.indexOf(this.myText) >= 0
})
}
}
})
</script>
监听属性
在watch对象中写函数,函数名使用data中的变量名,当这个变量发生变化,就会触发该函数的执行。
<div id="app">
<input type="text" v-model="myText"> ---->{{myText}}
</div>
<script>
new Vue({
el:'#app',
data:{
myText:''
},
watch:{
myText(val){
console.log('执行',val)
}
}
})
</script>
组件化开发之局部和全局组件
组件用于扩展 HTML 元素,封装可重用的代码,目的是复用
例如:有一个轮播,可以在很多页面中使用,一个轮播有js,css,html
组件把js,css,html放到一起,有逻辑,有样式,有html
组件的定义
<div id="app">
<h1>全局组件</h1>
<Child></Child>
<hr>
<h1>局部组件</h1>
<rain></rain>
</div>
<script>
// 全局组件
// 这些组件是全局注册的。也就是说它们在注册之后可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中
Vue.component('Child', {
template: `
<div>
<h1>我是一个组件--{{ myText }}</h1>
<button @click="handleClick">点击</button>
<br>
<input type="text" v-model="myText">
<jason></jason>
</div>
`,
data(){
return{
myText:'',
}
},
methods:{
handleClick(){
alert('xxx')
}
},
// 局部组件,写在Vue实例或者组件实例中
// 局部组件
components:{
jason:{
template: `
<div>
<h1>我是局部组件--jason</h1>
</div>
`,
}
}
})
new Vue({
el:'#app',
data:{},
// 局部组件
components: {
rain:{
template:`
<div>
<h1>我是局部组件</h1>
</div>
`,
}
}
})
</script>
1.自定义组件需要有一个root element(根元素),一般包裹在一个div中
2.父子组件的data,methods是无法共享
3.组件可以有data,methods,computed....,但是data 必须是一个函数
组件间通信
父传子(自定义属性)
在组件中添加props
,以字典形式接受需要的数据和类型
<div id="app">
输入需要传到子组件的数据:
<br>
<input type="text" v-model="name">
<Child :myname="name"></Child>
</div>
<script>
// 全局组件----子
Vue.component('Child', {
template: `
<div>
<h1>自定义属性--{{ myname }}</h1>
<br>
</div>
`,
// 自定义属性
props:{
'myname':String
}
})
// Vue实例(根组件)----父
new Vue({
el:'#app',
data:{
name:''
},
})
</script>
父传子(属性验证)
父组件传入的属性必选是子组件props
中所规定的属性类型,否则会报错
<div id="app">
输入需要传到子组件的数据:
<br>
<!-- 输入字符类型-->
<input type="text" v-model="name">
<!-- 输入数值类型-->
<input type="text" v-model="age">
<Child :myname="name" :myage="age"></Child>
</div>
<script>
// 全局组件----子
Vue.component('Child', {
template: `
<div>
<h1>自定义属性(字符串)--{{ myname }}</h1>
<h1>自定义属性(数值)--{{ myage }}</h1>
<br>
</div>
`,
props:{
'myname':String,
'myage':Number
}
})
// Vue实例(根组件)----父
new Vue({
el:'#app',
data:{
name:'',
age:null
},
})
</script>
子传父(自定义事件)
子组件可以使用$emit
触发父组件的自定义监听,在父组件中调用子组件时调用包含$emit
的事件,就可以接受到来自子组件的值
<div id="app">
<!-- 调用了包含$emit的自定义事件myevent传值,并且执行handleEvent函数接受值-->
<Child @myevent="handleEvent"></Child>
<br>
子组件传来的数据:{{name}}
</div>
<script>
// 全局组件----子
Vue.component('Child', {
template: `
<div>
<button @click="handleClick">点击向父组件传数据</button>
<br>
<input type="text" v-model="myText">
</div>
`,
data(){
return{
myText:'',
}
},
methods:{
// 定义myevent事件的函数
handleClick(){
this.$emit('myevent',this.myText)
}
},
})
// Vue实例(根组件)----父
new Vue({
el:'#app',
data:{
name:''
},
methods: {
// 接收值的函数
handleEvent(myText){
console.log('接受到了'+ myText)
this.name = myText
}
}
})
</script>
ref属性
ref放在标签上,拿到的是原生节点
ref放在组件上,拿到的是组件对象
通过这种方式实现子传父(this.$refs['ref得到的组件对象'].子组件的属性)
通过这种方式实现父传子(调用子组件方法传参数)
<div id="app">
<!-- ref放在标签上,拿到的是原生节点-->
<p ref="ppp"></p>
<h1>从子组件获得的值--{{name}}</h1>
<button @click="handleClick">数据传输</button>
<br>
<input type="text" v-model="name">
<hr>
<!-- ref放在组件上,拿到的是组件对象-->
<Child ref="ccc"></Child>
</div>
<script>
// 全局组件----子
Vue.component('Child', {
template: `
<div>
<h1>从父组件获得的值--{{ name }}</h1>
<input type="text" v-model="name">
<br>
</div>
`,
data(){
return{
name:''
}
},
methods: {
name1(aa){
this.name = aa
}
}
})
// Vue实例(跟组件)----父
new Vue({
el:'#app',
data:{
name:''
},
methods:{
handleClick(){
// 通过这种方式实现父传子(调用子组件方法传参数)
this.$refs['ccc'].name1('传参')
// 父传子(调用子组件属性传参数)
this.$refs['ccc'].name = this.name
// 通过这种方式实现子传父(this.$refs['ref得到的组件对象'].子组件的属性)
this.name = this.$refs['ccc'].name
}
}
})
</script>
数据总线
不同层级的不通组件通信
数据总线
vuex(状态管理器)
cookie,localStorage,sessionStorage
<div id="app">
<child1></child1>
<hr>
<child2></child2>
</div>
<script>
// 1 定义一个数据总线
var bus = new Vue() //new一个vue的实例,就是中央事件总线
// 2 定义两个全局组件 一个用于发生数据 一个用于储存数据
Vue.component('child1', {
template: `
<div>
<input type="text" v-model="myText">
<button @click="handleClick">点我</button>
</div>`,
data() {
return {
myText: ''
}
},
methods: {
handleClick() {
bus.$emit('suibian',this.myText)
}
}
})
Vue.component('child2', {
template: `
<div>
接受到的数据是:{{ myText }}
</div>`,
data() {
return {
myText: ''
}
},
mounted(){
// 等着,监听,如果谁触发我,我就执行
// $on() 监听当前实例上的自定义事件
bus.$on('suibian',(name)=>{
this.myText=name
})
}
})
var vm = new Vue({
el: '#app',
data: {},
})
</script>
动态组件
通过component
配合is
属性,决定显示的组件是哪个
keep-alive
保证组件切换走后不被销毁
<div id="app">
<ul>
<li @click="who='home'">首页</li>
<li @click="who='goods'">商品</li>
<li @click="who='order'">订单</li>
</ul>
<!-- keep-alive保证组件切换走后不被销毁-->
<keep-alive>
<!-- component + is决定显示的组件是哪个-->
<component :is="who">
</component>
</keep-alive>
</div>
<script>
Vue.component('home', {
template: `
<div>
首页
</div>`,
})
Vue.component('goods', {
template: `
<div>
商品
<input type="text">
</div>`,
})
Vue.component('order', {
template: `
<div>
订单
</div>`,
})
var vm = new Vue({
el: '#app',
data: {
// 默认显示home组件
who: 'home'
},
})
</script>
slot插槽 (内容分发)
a. 单个slot
b. 具名slot
混合父组件的内容与子组件自己的模板-->内容分发
父组件模板的内容在父组件作用域内编译;子组件模板的内容在子组件作用域内编译。
<div id="app">
<home>
<!-- 父组件模板的内容-->
<div><button>美女</button></div>
</home>
</div>
<script>
Vue.component('home', {
template: `
<div>
<input type="text">
<hr>
<!--插槽-->
<slot></slot>
<!--子组件模板的内容-->
<button>点我</button>
</div>`,
})
var vm = new Vue({
el: '#app',
data: {
},
})
</script>
具名插槽
可以指定插入的位置
<div id="app">
<home>
<!-- 具名插槽a的父组件内容-->
<div slot="a">我是div</div>
<!-- 具名插槽b的父组件内容-->
<img src="https://tva1.sinaimg.cn/large/00831rSTly1gd1u0jw182j30u00u043b.jpg" alt="" slot="b">
</home>
</div>
<script>
Vue.component('home', {
template: `
<div>
<input type="text">
<hr>
<!--具名插槽a-->
<slot name="a"></slot>
navbar
<!--具名插槽b-->
<slot name="b"></slot>
<button>点我</button>
</div>`,
})
var vm = new Vue({
el: '#app',
data: {
},
})
</script>