一、计算属性
计算属性是基于它们的依赖进行缓存的
计算属性只有在它的相关依赖发生改变时才会重新求值
计算属性就像Python
中的property
,可以把方法/函数
伪装成属性
1.通过计算属性实现名字首字母大写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首字母大写</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<!--大段的代码写在这里不好,使用计算属性-->
模板插值:
{{myText.substring(0,1).toUpperCase()+myText.substring(1)}}
<p>普通方法:{{getNameMethod()}}</p>
<!--区别是在同一个页面中使用多次计算属性,不会多次执行-->
<p>计算属性:{{getName}}</p>
<!--普通方法要加括号-->
</div>
</body>
<script>
var vm = new Vue({
el: '#box',
data: {
myText: 'darker',
},
computed: {
getName() { // 依赖的状态改变了,会重新计算
return this.myText.substring(0, 1).toUpperCase() + this.myText.substring(1)
}
},
methods: {
getNameMethod() {
return this.myText.substring(0, 1).toUpperCase() + this.myText.substring(1)
}
}
})
</script>
</html>
2.通过计算属性重写过滤案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>通过计算属性重写过滤案例</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<p><input type="text" v-model="myText" placeholder="请输入要筛选的内容:"></p>
<ul>
<li v-for="data in newList">{{data}}</li>
</ul>
</div>
</body>
<script>
var vm = new Vue({
el: '#box',
data: {
myText: '',
dataList: ['a', 'at', 'atom', 'be', 'beyond', 'cs', 'csrf'],
},
computed: {
newList() {
return this.dataList.filter(item => {
return item.indexOf(this.myText) > -1 // 返回索引大于1的元素:>-1 就表示包含在其中
})
}
}
})
</script>
</html>
二、监听属性
属性如果发生变化,就会执行某个函数
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="app">
<h1>监听属性</h1>
<input type="text" v-model="username">---->{{username}}
</div>
</body>
<script>
let vm = new Vue({
el: '#app',
data: {
username: '',
},
methods: {},
computed: {},
watch: {
username(newValue, oldValue) {
console.log('老值', oldValue)
console.log('新值', newValue)
console.log('我发生变化了')
}
}
})
</script>
</html>
三、Vue生命周期
1.生命周期
钩子函数 | 描述 |
---|---|
beforeCreate | 创建Vue实例之前调用 |
created | 创建Vue实例成功后调用(可以在此处发送异步请求后端数据) |
beforeMount | 渲染DOM之前调用 |
mounted | 渲染DOM之后调用 |
beforeUpdate | 重新渲染之前调用(数据更新等操作时,控制DOM重新渲染) |
updated | 重新渲染完成之后调用 |
beforeDestroy | 销毁之前调用 |
destroyed | 销毁之后调用 |
create
let vm = new Vue()
mount
挂载,把div挂载到组件中
update
let vm = new Vue({
el: '#box',
data: {
isShow: true // 修改这个内容
},
methods: {
handleClick() {
console.log('我是根组件')
}
}
})
组件销毁 - 给组件写一个定时器
setTimeout() // 延迟3s干什么事
setInterval() // 延迟3s干什么事
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>生命周期</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<child v-if="isShow"></child>
<br>
<button @click="terminate">删除子组件</button>
<button @click="reborn">显示子组件</button>
</div>
</body>
<script>
Vue.component('child', {
template: `
<div>
{{name}}
<button @click="name='Darker1'">更新数据1</button>
<button @click="name='Darker2'">更新数据2</button>
</div>`,
data() {
return {
name: 'Darker1',
}
},
beforeCreate() {
console.group('当前状态:beforeCreate')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
created() {
console.group('当前状态:created')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
beforeMount() {
console.group('当前状态:beforeMount')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
mounted() {
console.group('当前状态:mounted')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
beforeUpdate() {
console.group('当前状态:beforeUpdate')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
updated() {
console.group('当前状态:updated')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
beforeDestroy() {
console.group('当前状态:beforeDestroy')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
destroyed() {
console.group('当前状态:destroyed')
console.log('当前el状态:', this.$el)
console.log('当前data状态:', this.$data)
console.log('当前name状态:', this.name)
},
})
let vm = new Vue({
el: '#box',
data: {
isShow: true
},
methods: {
terminate() {
this.isShow = false
},
reborn() {
this.isShow = true
}
}
})
</script>
</html>
四、组件介绍及使用
1.组件是什么?有什么用?
组件就是:扩展 HTML 元素,封装可重用的代码
,目的是复用
例如:有一个轮播图,可以在很多页面中使用,一个轮播有js,css,html
组件把js,css,html放到一起,有逻辑,有样式,有html
组件的分类:
- 全局组件:可以放在根中
- 局部组件:
工程化开发之后:
1个组件 就是1个xx.vue
2、组件的注册方式
定义全局组件,绑定事件,编写样式
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>全局组件</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<div @click="handleClick">我是根部组件</div>
<global></global>
<ul>
<li v-for="i in 4">
<global></global>
</li>
</ul>
</div>
</body>
<script>
// 创建1个组件对象(全局组件)
Vue.component('global', {
template: `
<div>
<div style="background: rgba(255,104,104,0.7); padding: 5px;" @click="handleClick">我是头部组件</div>
<div v-if="isShow">显示消失</div>
</div>
`,
methods: {
handleClick() {
console.log('我被点击了')
this.isShow = !this.isShow
}
},
data() {
return {
isShow: true
}
}
})
let vm = new Vue({
el: '#box',
data: {
isShow: true
},
methods: {
handleClick() {
console.log('我被点击了 我是根组件')
}
}
})
</script>
</html>
3. 定义局部组件
① 局部组件 放在 Vue实例(根组件) 中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>局部组件</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box" style="max-width: 300px">
<local></local>
<global></global>
</div>
</body>
<script>
// 创建1个组件对象(全局组件)
Vue.component('global', {
template: `
<div>
<div style="background: rgba(255,104,104,0.7); padding: 5px 10px; border-radius: 5px;margin: 5px 0;">
我是全局组件
</div>
</div>
`,
})
let vm = new Vue({
el: '#box',
data: {},
// 创建1个组件对象(局部组件)
components: {
local: { // local 组件名
template: `
<div>
<div style="background: rgba(104,255,104,0.7); padding: 5px 10px; border-radius: 5px; margin: 3px 50px 3px 0;"
@click="handleClick">我是局部组件
</div>
</div>
`, // 组件的模板
methods: {
handleClick() {
console.log('我被点击了')
}
}
}
}
})
</script>
</html>
② 局部组件 放在 全局组件 中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>局部组件</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box" style="max-width: 300px">
<ul>
<li v-for="i in 3">
<global></global>
</li>
</ul>
</div>
</body>
<script>
// 创建1个组件对象(全局组件)
Vue.component('global', {
template: `
<div>
<div style="background: rgba(255,104,104,0.7); padding: 5px 10px; border-radius: 5px;margin: 5px 0;">
我是全局的组件
</div>
<local></local>
<local></local>
<br>
</div>
`,
// 创建1个组件对象(局部组件)
components: {
local: {
template: `
<div>
<div style="background: rgba(104,255,104,0.7); padding: 5px 10px; border-radius: 5px; margin: 3px 50px 3px 0;">我是局部组件</div>
</div>
`,
}
}
})
let vm = new Vue({
el: '#box',
})
</script>
</html>
注意点:
- 定义的组件(body中的位置)必须要放在Vue实例(这也是一个组件 根组件)中
- 局部组件 必须放在 全局组件/根组件 中,无法单独使用
- 定义的组件必须在Vue实例的上方
五、组件间通信
1.组件间父传子
- 在全局组件中自定义属性:
<global :myname="name" :myage="19"></global>
- 在组件中获取:
{{myname}}
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>组件</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<!-- myName是自定义属性 -->
<global myname="name" myage="18"></global>
<global :myname="name" :myage="19"></global>
<global :myname="'Ben'" :myage="20"></global>
</div>
</body>
<script>
// 创建1个组件对象(全局组件/子组件)
Vue.component('global', {
template: `
<div>
<div style="background: rgba(255,104,104,0.7); padding: 5px;">全局组件/子组件</div>
{{myname}}
{{myage}}
</div>
`,
props: ['myname', 'myage']
})
// 父组件
let vm = new Vue({
el: '#box',
data: {
name: 'darker'
},
})
</script>
</html>
属性验证
- 限制父传子的变量类型
props: {
myname: String,
isshow: Boolean
}
- 父传子时候注意以下区别
<global :myname="name" :is_show="'false'"></global>
<global :myname="name" :is_show="false"></global>
<global :myname="name" :is_show="is_show"></global>
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>组件</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<!-- myName是自定义属性 -->
<!-- <global :myname="name" :myage="19" :isshow="'false'"></global>-->
<global :my_name="name" :is_show="is_show"></global>
<global :my_name="name" :is_show="false"></global>
</div>
</body>
<script>
// 创建1个组件对象(全局组件/子组件)
Vue.component('global', {
template: `
<div>
<div style="background: rgba(255,104,104,0.7); padding: 5px;">我是子组件:{{is_show}}</div>
<span>{{my_name}}</span>
</div>
`,
props: {
my_name: String,
is_show: Boolean
}
})
// 父组件
let vm = new Vue({
el: '#box',
data: {
name: 'darker',
is_show: true
},
})
</script>
</html>
2.子传父(通过事件)
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>子传父</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<global @my_event="handleClick($event)"></global>
</div>
</body>
<script>
// 创建1个组件对象(全局组件/子组件)
Vue.component('global', {
template: `
<div>
<div style="background: rgba(255,104,104,0.7); padding: 5px;">全局组件/子组件</div>
<button @click="handleNav">点我</button>
</div>
`,
data() {
return {
name: 'Darker'
}
},
methods: {
handleNav() {
console.log('我是子组件的函数')
this.$emit('my_event', 666, 777, this.name)
}
}
})
// 父组件
let vm = new Vue({
el: '#box',
data: {},
methods: {
handleClick(a,b,c) {
console.log('我是父组件的函数')
console.log(a)
console.log(b)
console.log(c)
}
}
})
</script>
</html>
3.子传父(控制子组件的显示和隐藏)
点击子组件,就会触发父组件的某个函数执行
示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>子传父</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<global @my_event="handleClick($event)"></global>
</div>
</body>
<script>
// 创建1个组件对象(全局组件/子组件)
Vue.component('global', {
template: `
<div>
<div style="background: rgba(255,104,104,0.7); padding: 5px;">全局组件/子组件</div>
<button @click="handleNav">点我</button>
</div>
`,
data() {
return {
name: 'Darker'
}
},
methods: {
handleNav() {
console.log('我是子组件的函数')
this.$emit('my_event', 666, 777, this.name)
}
}
})
// 父组件
let vm = new Vue({
el: '#box',
data: {},
methods: {
handleClick(a,b,c) {
console.log('我是父组件的函数')
console.log(a)
console.log(b)
console.log(c)
}
}
})
</script>
</html>
小案例
- 子组件有1个按钮 和 1个输入框,子组件输入完内容后,数据在父组件中展示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>子传父 小案例</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<global @my_event="handleShow($event)"></global>
<br>
<div>父组件接收到的数据:{{name}}</div>
</div>
</body>
<script>
// 创建1个组件对象(全局组件/子组件)
Vue.component('global', {
template: `
<div>
<input type="text" v-model="myText">
<button @click="handleClick">点我传数据</button>
</div>
`,
data() {
return {
myText: ''
}
},
methods: {
handleClick() {
this.$emit('my_event', this.myText)
}
}
})
// 父组件
let vm = new Vue({
el: '#box',
data: {
name: ''
},
methods: {
handleShow(a) {
this.name = a
}
}
})
</script>
</html>
4.ref属性(也可以实现组件间通信:子和父都可以实现通信)
- ref放在
标签
上,拿到的是原生的DOM节点
- ref放在
组件
上,拿到的是组件对象
,对象中的数据、函数 都可以直接使用 - 通过这种方式实现子传父(this.$refs.mychild.text)
- 通过这种方式实现父传子(调用子组件方法传参数)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>子传父</title>
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.12/vue.min.js"></script>
</head>
<body>
<div id="box">
<input type="text" ref="myRef">
<button @click="handleButton">点我</button>
</div>
</body>
<script>
// 创建1个组件对象(全局组件/子组件)
Vue.component('global', {
template: `
<div>
<input type="text" v-model="myText">
</div>
`,
data() {
return {
myText: ''
}
},
methods: {
handleClick() {
this.$emit('my_event', this.myText)
this.$emit('my_event', this.innerHTML)
}
}
})
// 父组件
let vm = new Vue({
el: '#box',
data: {
name: ''
},
methods: {
handleShow(a) {
this.name = a
},
handleButton() {
console.log(this.$refs)
console.log(this.$refs.myRef)
console.log(this.$refs.myRef.value)
}
}
})
</script>
</html>