组件
局部组件使用
局部组件,在哪里使用就去哪里挂载。
页面布局:头部、侧边栏、内容区域
1.页面中肯定有一个入口组件,需要先声明入口组件。 2.挂载子组件 3.使用子组件
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
</style>
</head>
<body>
<div id='app'>
</div>
<script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var Vmain = {
template:`
<div class='main'>
这里是入口
</div>
`
}
var app = new Vue({
el: '#app',
template: `<Vmain />`,
data: {
msg:"heh",
},
components: {
Vmain:Vmain
},
});
</script>
</body>
</html>
组件渲染到了 页面 增加头部组件,侧边栏组件,内容组件。 凡是用组件记住这句话:先声子,挂子,用子。
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
*{
padding: 0,
margin:0;
}
.main{
width: 100%;
}
.head{
width: 100%;
height: 70px;
background-color: purple;
text-align: center;
columns: #fff;
font-size: 20px;
line-height: 70px;
}
.wrap{
width: 100%;
height: 1200px;
}
.wrap .aside{
width: 20%;
height: 1200px;
background-color: green;
float: left;
}
.wrap .content{
width: 80%;
height: 1200px;
background-color: yellow;
float: left;
}
</style>
</head>
<body>
<div id='app'>
</div>
<script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var Vheader = {
template:`
<header class='head'>
这里是头部
</header>
`
}
var Vaside = {
template:`
<div class='aside'>
我是侧边栏
</div>
`
}
var Vcontent = {
template:`
<div class='content'>
我是内容
</div>
`
}
var Vmain = {
template:`
<div class='main'>
<Vheader></Vheader>
<div class='wrap'>
<Vaside />
<Vcontent />
</div>
</div>
`,
components:{
Vheader,
Vaside,
Vcontent
}
}
var app = new Vue({
el: '#app',
template: `<Vmain />`,
data: {
msg:"heh",
},
components: {
Vmain:Vmain
},
});
</script>
</body>
</html>
向子组件中传递信息
prop 单向数据流传递数据
从父到子的单向数据流传递。 app是入口组件,从入口组件将数据传输到各个子组件,就是单向数据流。在入口组件向后端交互获取一个数据,获取到的数据在app的子组件、孙子组件中都可以使用。 相比较之前的做法:在哪里需要数据就向后端发送请求获取数据,如果三个孙子组件需要同一份数据,就要向后台发送三次请求。。好处是减少了请求的发送次数。
Prop 是你可以在组件上注册的一些自定义 attribute。当一个值传递给一个 prop attribute 的时候,它就变成了那个组件实例的一个 property 一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。
传递方法: 1.在子组件中自定义特性,即props:[‘自定义属性1’,‘自定义属性2’] 当一个值传递给一个prop特性的时候,它就变成了那个组件实例的一个属性,那么我们就可以像访问data中的值一样去访问。 2.要从父组件中导入到子组件内部,绑定自定义的属性<Vheader :title = '父组件中的data声明的数据属性'>
将数据从Vue对象中传递到Vheader和Vaside中,像访问data数据一样的方式去访问。
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
*{
padding: 0,
margin:0;
}
.main{
width: 100%;
}
.head{
width: 100%;
height: 70px;
background-color: purple;
text-align: center;
columns: #fff;
font-size: 20px;
line-height: 70px;
}
.wrap{
width: 100%;
height: 1200px;
}
.wrap .aside{
width: 20%;
height: 1200px;
background-color: green;
float: left;
}
.wrap .content{
width: 80%;
height: 1200px;
background-color: yellow;
float: left;
}
</style>
</head>
<body>
<div id='app'>
</div>
<script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var Vheader = {
template:`
<header class='head'>
这里是头部,{{ title }}
</header>
`,
props:['title'],
}
var Vaside = {
template:`
<div class='aside'>
我是侧边栏,{{ title }}
</div>
`,
props:['title'],
}
var Vcontent = {
template:`
<div class='content'>
我是内容
</div>
`,
}
var Vmain = {
template:`
<div class='main'>
<Vheader :title='title'></Vheader>
<div class='wrap'>
<Vaside :title='title' />
<Vcontent />
</div>
</div>
`,
components:{
Vheader,
Vaside,
Vcontent
},
props:['title'],
}
var app = new Vue({
el: '#app',
template: `<Vmain :title='text'/>`,
data: {
msg:"heh",
text:"我要传宗接代"
},
components: {
Vmain:Vmain
},
});
</script>
</body>
</html>
图解流程 页面效果:
prop传递数据的例子
更改data中的值,子组件中的值也会相应的变化。
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
*{
padding: 0,
margin:0;
}
.main{
width: 100%;
}
.head{
width: 100%;
height: 70px;
background-color: purple;
text-align: center;
columns: #fff;
font-size: 20px;
line-height: 70px;
}
.wrap{
width: 100%;
height: 1200px;
}
.wrap .aside{
width: 20%;
height: 1200px;
background-color: green;
float: left;
}
.wrap .content{
width: 80%;
height: 1200px;
background-color: yellow;
float: left;
}
</style>
</head>
<body>
<div id='app'>
</div>
<script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var Vheader = {
template:`
<header class='head'>
这里是头部,{{ title }}
</header>
`,
props:['title'],
}
var Vaside = {
template:`
<div class='aside'>
我是侧边栏,{{ title }}
</div>
`,
props:['title'],
}
var Vcontent = {
template:`
<div class='content'>
我是内容
<ul>
<li v-for='item in posts' :key='item.id'>
{{item.id}}
{{item.content}}
</li>
</ul>
</div>
`,
props:['posts'],
}
var Vmain = {
template:`
<div class='main'>
<Vheader :title='title'></Vheader>
<div class='wrap'>
<Vaside :title='title' />
<Vcontent :posts='appPosts' />
</div>
</div>
`,
components:{
Vheader,
Vaside,
Vcontent
},
props:['title', 'appPosts'],
}
var app = new Vue({
el: '#app',
template: `<Vmain :title='text' :appPosts='posts'/>`,
data: {
msg:"heh",
text:"默默地",
posts:[
{id:1,title:"组件中的传值",content:"通过props传值"},
{id:2,title:"组件中的传值2",content:"通过props传值2"},
{id:3,title:"组件中的传值3",content:"通过props传值3"}
]
},
components: {
Vmain:Vmain
},
});
</script>
</body>
</html>
向父级组件传递信息
我们可以调用内建的$emit 方法并传入事件名,来向父级组件触发一个事件。
传递流程: 1.在子组件中的某个按钮定义原生事件,在事件驱动程序中调用this.$emit('自定义事件名',传递的参数) ,向父级组件触发emit指定的自定义事件。 2.在父组件中的子组件标签中,绑定自定义事件名(是子组件中emit指定的自定义事件名)
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
*{
padding: 0,
margin:0;
}
.main{
width: 100%;
}
.head{
width: 100%;
height: 70px;
background-color: purple;
text-align: center;
columns: #fff;
font-size: 20px;
line-height: 70px;
}
.wrap{
width: 100%;
height: 1200px;
}
.wrap .aside{
width: 20%;
height: 1200px;
background-color: green;
float: left;
}
.wrap .content{
width: 80%;
height: 1200px;
background-color: yellow;
float: left;
}
</style>
</head>
<body>
<div id='app'>
</div>
<script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var Vheader = {
template:`
<header class='head'>
这里是头部,{{ title }}
</header>
`,
props:['title'],
}
var Vaside = {
template:`
<div class='aside'>
我是侧边栏,{{ title }}
</div>
`,
props:['title'],
}
var Vcontent = {
template:`
<div class='content'>
我是内容
<ul>
<li v-for='item in posts' :key='item.id'>
{{item.id}}
{{item.content}}
</li>
</ul>
<button @click="change_font_size">修改文本大小</button>
</div>
`,
props:['posts'],
methods:{
change_font_size(){
this.$emit('font_size_update', 3)
}
}
}
var Vmain = {
template:`
<div class='main' :style="{fontSize:font_size+'px'}">
<Vheader :title='title'></Vheader>
<div class='wrap'>
<Vaside :title='title' />
<Vcontent :posts='appPosts' @font_size_update='clickHandle' />
</div>
</div>
`,
components:{
Vheader,
Vaside,
Vcontent
},
props:['title', 'appPosts'],
data(){
return {
font_size:18
}
},
methods:{
clickHandle(value){
this.font_size += value;
}
}
}
var app = new Vue({
el: '#app',
template: `<Vmain :title='text' :appPosts='posts'/>`,
data: {
msg:"heh",
text:"默默地",
posts:[
{id:1,title:"组件中的传值",content:"通过props传值"},
{id:2,title:"组件中的传值2",content:"通过props传值2"},
{id:3,title:"组件中的传值3",content:"通过props传值3"}
]
},
components: {
Vmain:Vmain
},
});
</script>
</body>
</html>
图解流程 效果展示
公共组件
只要创建完,就可以在任意的组件中去使用。
// 第一个参数是公共组件的名字,第二个参数是options
// optoins跟new Vue()实例化中的options是一样的,但是要注意,不管是公共组件还是局部组件,data必须是一个函数,函数一定要返回{}
Vue.component('Vbtn', {
template:`<button>登录</button>`
})
内置组件slot,来将数据发到公共组件
<slot> 元素作为承载分发内容的出口。 例子一:简单使用
Vue.component('Vbtn', {
template:`<button><slot></slot></button>`
})
var Vheader = {
template:`
<header class='head'>
这里是头部,{{ title }}
<Vbtn>注册</Vbtn>
<Vbtn>登录</Vbtn>
<Vbtn>登出</Vbtn>
</header>
`,
props:['title'],
}
例子二:结合Element使用,不同样式的按钮 Element地址:https://element.eleme.cn/2.12/#/zh-CN/component/button
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
*{
padding: 0,
margin:0;
}
.head{
width: 100%;
height: 70px;
background-color: purple;
text-align: center;
columns: #fff;
font-size: 20px;
line-height: 70px;
}
.default{
display: inline-block;
line-height: 1;
white-space: nowrap;
cursor: pointer;
background: #fff;
border: 1px solid #dcdfe6;
color: #606266;
text-align: center;
box-sizing: border-box;
outline: none;
margin: 0;
transition: .1s;
font-weight: 500;
padding: 12px 20px;
font-size: 14px;
border-radius: 4px;
}
.success{
color: #fff;
background-color: #67c23a;
border-color: #67c23a;
}
.primary{
color: #fff;
background-color: #409eff;
border-color: #409eff;
}
</style>
</head>
<body>
<div id='app'>
</div>
<script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
Vue.component('Vbtn', {
template:`<button id='Vbtn' class='default' :class='type'><slot></slot></button>`,
props: ['type']
})
var Vheader = {
template:`
<header class='head'>
<Vbtn type='primary'>注册</Vbtn>
<Vbtn type='success'>登录</Vbtn>
<Vbtn type='default'>登出</Vbtn>
</header>
`,
data(){
return {
}
},
}
var app = new Vue({
el: '#app',
template: `<Vheader/>`,
data: {
},
components: {
Vheader:Vheader
},
});
</script>
</body>
</html>
图解流程 通过父子组件通信传递数据。 效果展示:
过滤器
局部过滤器
Vue.js 允许你自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用在两个地方:双花括号插值({{ message | capitalize }} )和 v-bind 表达式(<div v-bind:id="rawId | formatId"></div> ) (后者从 2.1.0+ 开始支持)。 定义和使用局部过滤器
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
*{
padding: 0,
margin:0;
}
.head{
width: 100%;
height: 70px;
background-color: purple;
text-align: center;
columns: #fff;
font-size: 20px;
line-height: 70px;
}
</style>
</head>
<body>
<div id='app'>
</div>
<script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var Vheader = {
template:`
<header class='head'>
<input type="text" name="xx" v-model='msg'>
<p>{{ msg | price }}</p>
</header>
`,
data(){
return {
msg: 0,
}
},
filters:{
price: function(value){
return '$'+value
}
}
}
var app = new Vue({
el: '#app',
template: `<Vheader/>`,
data: {
},
components: {
Vheader:Vheader
},
});
</script>
</body>
</html>
全局过滤器
Vue.filter('reverse', function(value){
return value.split('').reverse().join('')
})
侦听属性watch
其主要的作用是检测单个属性。你有一些数据需要随着其它数据变动而变动时。
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
*{
padding: 0,
margin:0;
}
</style>
</head>
<body>
<div id='app'>
</div>
<script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var Vheader = {
template:`
<header class='head'>
<input type="text" name="" v-model='msg'>
<p>{{msg}}</p>
</header>
`,
data(){
return {
msg: '',
}
},
watch: {
msg: function(value){
console.log(value);
if (value=='I am'){
console.log(value + 'dsb')
}
}
}
}
var app = new Vue({
el: '#app',
template: `<Vheader/>`,
data: {
},
components: {
Vheader:Vheader
},
});
</script>
</body>
</html>
监听到文本款内输入的值,如果是I am ,就增加额外的log打印。 在watch指定的方法中,还可以使用this.xx 拿到数据属性中其他数据。但是当其他数据发生改变时不会去监听,只监听key指定的名字。
计算属性
侦听多个数据属性的变化。
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护. 对于任何复杂逻辑,你都应当使用计算属性。
实际上,计算属性可以完全用函数来实现
两种方式的最终结果确实是完全相同的。然而,不同的是计算属性是基于它们的响应式依赖进行缓存的。只在相关响应式依赖发生改变时它们才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
*{
padding: 0,
margin:0;
}
</style>
</head>
<body>
<div id='app'>
</div>
<script type="text/javascript" src="./node_modules/vue/dist/vue.js"></script>
<script type="text/javascript">
var Vheader = {
template:`
<header class='head'>
{{person_info}}
<button @click='change_info'>修改</button>
</header>
`,
data(){
return {
name: 'xxx',
age:19,
}
},
computed: {
person_info:function(){
return `${this.name}现在${this.age},已经成年了`
}
},
methods:{
change_info(){
this.name='zhansan',
this.age=23
}
}
}
var app = new Vue({
el: '#app',
template: `<Vheader/>`,
data: {
},
components: {
Vheader:Vheader
},
});
</script>
</body>
</html>
生命周期的钩子函数
钩子可以认为就是某个函数。 声明周期图示:
beforeCreate && created
组件创建之前和组件创建之后。 created方法应用较多,一般是向后端发送ajax请求获取数据,在修改数据属性,从而影响到页面的显示。
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
*{
padding: 0,
margin:0;
}
</style>
</head>
<body>
<div id='app'>
<Test />
</div>
<script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script>
<script type="text/javascript">
var Test = {
template:`<h1>{{msg}}</h1>`,
data(){
return {
msg:'hhh',
}
},
beforeCreate(){
console.log(this.msg)
},
created(){
console.log(this.msg)
this.msg='xxx'
console.log(this.msg)
}
}
var app = new Vue({
el: '#app',
data: {
},
components:{
Test:Test
}
});
</script>
</body>
</html>
页面显示:
beforeMount && mounted
挂载之前和挂载之后。装载数据到DOM之前和之后。 mounted可以获取真实存在的DOM元素,即组件和数据都加载到页面中。
beforeUpdate && updated
数据更新之前和数据更新之后的钩子函数。
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
*{
padding: 0,
margin:0;
}
</style>
</head>
<body>
<div id='app'>
<Test />
</div>
<script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script>
<script type="text/javascript">
var Test = {
template:`
<div>
<h1>{{msg}}</h1>
<button @click="change_handle">修改</button>
</div>
`,
data(){
return {
msg:'123',
}
},
methods:{
change_handle(){
this.msg='woshishui'
}
},
beforeUpdate(){
console.log(document.getElementById('app').innerHTML);
},
updated(){
console.log(document.getElementById('app').innerHTML);
}
}
var app = new Vue({
el: '#app',
data: {
},
components:{
Test:Test
}
});
</script>
</body>
</html>
页面显示:
beforeDestroy && destroyed
在组件销毁之前和销毁之后,我们可以通过v-if 来控制组件的销毁创建。 销毁创建太耗费网页性能,所以不会使用到。
activated && deactivated
在组件的激活和停用时调用的钩子函数,要用到内置组件<keep_alive></keepp_alive> ,能让写在里面的组件产生缓存。 在keep_alive中编写的组件,通过v-if 来控制组件时,不会走创建和销毁,当v-if=true 时从缓存从拉出来显示,调用activated钩子方法,当v-if=false 时,放入缓存,调用deactivated方法。
使用$ref获取DOM元素
1.给标签添加一个ref属性,<button ref='btn'>按钮1</button> 2.在组件中通过this.$refs.btn 拿到DOM对象。
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
*{
padding: 0,
margin:0;
}
</style>
</head>
<body>
<div id='app'>
<Test />
</div>
<script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script>
<script type="text/javascript">
var Test = {
template:`
<div>
<h1 ref='h'>{{msg}}</h1>
<button ref='btn' @click="change_handle">修改</button>
</div>
`,
data(){
return {
msg:'123',
}
},
methods:{
change_handle(){
this.msg='woshishui'
}
},
beforeCreate(){
console.log(this.$refs.btn)
},
created(){
console.log(this.$refs.btn)
},
beforeMount(){
console.log(this.$refs.btn)
},
mounted(){
console.log(this.$refs.btn)
},
beforeUpdate(){
},
updated(){
}
}
var app = new Vue({
el: '#app',
data: {
},
components:{
Test:Test
}
});
</script>
</body>
</html>
钩子函数中,如果想对DOM进行操作,必须是在mounted和其之后进行,原因是虚拟DOM
如果是给组件绑定的ref属性,那么通过this.$refs.xxx 取到的是组件对象。
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
*{
padding: 0,
margin:0;
}
</style>
</head>
<body>
<div id='app'>
<Test />
</div>
<script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script>
<script type="text/javascript">
Vue.component('subApp', {
template:`<div></div>`
});
var Test = {
template:`
<div>
<h1 ref='h'>{{msg}}</h1>
<button ref='btn' @click="change_handle">修改</button>
<subApp ref='app'></subApp>
</div>
`,
data(){
return {
msg:'123',
}
},
methods:{
change_handle(){
this.msg='woshishui'
}
},
beforeCreate(){
console.log(this.$refs.app)
},
created(){
console.log(this.$refs.app)
},
beforeMount(){
console.log(this.$refs.app)
},
mounted(){
console.log(this.$refs.app)
},
beforeUpdate(){
},
updated(){
}
}
var app = new Vue({
el: '#app',
data: {
},
components:{
Test:Test,
}
});
</script>
</body>
</html>
$属性
$refs :获取组件内的元素
$parent:获取当前组件的父组件
$chidren:获取当前组件的子组件
$root:获取new Vue的实例化对象
$el:获取当前对象的DOM元素
使用$nextTick的特殊情况
有一个需求:页面中有一个input标签,在加载时自动获取焦点。
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
*{
padding: 0,
margin:0;
}
</style>
</head>
<body>
<div id='app'>
<Test />
</div>
<script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script>
<script type="text/javascript">
var Test = {
template:`
<div>
<input type="text" name="" ref='fos' v-if='isShow'>
</div>
`,
data(){
return {
isShow:true
}
},
methods:{
},
mounted(){
this.$refs.fos.focus()
},
beforeUpdate(){
},
updated(){
}
}
var app = new Vue({
el: '#app',
data: {
},
components:{
Test:Test
}
});
</script>
</body>
</html>
页面刷新自动获取焦点 需求2:在页面刷新时显示input标签,再获取焦点
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
*{
padding: 0,
margin:0;
}
</style>
</head>
<body>
<div id='app'>
<Test />
</div>
<script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script>
<script type="text/javascript">
var Test = {
template:`
<div>
<input type="text" name="" ref='fos' v-if='isShow'>
</div>
`,
data(){
return {
isShow:false
}
},
methods:{
},
mounted(){
this.isShow=true
this.$refs.fos.focus()
},
beforeUpdate(){
},
updated(){
}
}
var app = new Vue({
el: '#app',
data: {
},
components:{
Test:Test
}
});
</script>
</body>
</html>
页面效果: 并没有实现要求的功能,是因为Vue实现响应式并不是数据发生变化之后DOM立刻发生变化,而是按一定的策略进行DOM的更新。所以此时拿到不input对象。
策略就是$nextTick ,是在下次DOM更新循环结束之后执行的延迟回调,在修改数据之后是使用$nextTick ,则可以在会调用获取更新之后的DOM.
代码更新
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
*{
padding: 0,
margin:0;
}
</style>
</head>
<body>
<div id='app'>
<Test />
</div>
<script type="text/javascript" src="./node_modules/vue/dist/vue.min.js"></script>
<script type="text/javascript">
var Test = {
template:`
<div>
<input type="text" name="" ref='fos' v-if='isShow'>
</div>
`,
data(){
return {
isShow:false
}
},
methods:{
},
mounted(){
this.isShow=true
this.$nextTick(function(){
this.$refs.fos.focus()
});
},
beforeUpdate(){
},
updated(){
}
}
var app = new Vue({
el: '#app',
data: {
},
components:{
Test:Test
}
});
</script>
</body>
</html>
需求2功能完成。
|