component 组件 computed计算属性(2018/11/20)
一、 computed 计算属性
在模板中放入太多的逻辑会让模板过重且难以维护, 所以,对于任何复杂逻辑,包括运算、函数调用等,你都应当使用计算属性。
计算属性还有两个很实用的小技巧容易被忽略:一是计算属性可以依赖其他计算属性; 二是计算属性不仅可以依赖当前Vue 实例的数据,还可以依赖其他实例的数据
<div id="app1"></div>
<div id="app2">{{ reverseText}}</div>
<script>
var app1 = new Vue({
el: '#app1',
data: {
text: 'haahaha'
}
});
var app2 = new Vue({
el: '#app2',
computed: {
reverseText: function(){
return app1.text.split('').reverse().join(''); //使用app1的数据进行计算 }
}
});
</script>
二 v-bind:class 绑定class
在将 v-bind 用于 class 和 style 时,Vue.js 做了专门的增强。表达式结果的类型除了字符串( 不建议这样使用,因为string值是固定不变的,无法实现动态改变class的需求)之外,还可以是对象或数组。
对象的形式: {"类名":"关系表达式",...}
数组的形式: ["类名",......]
写在指令中的值会被视作表达式,如javascript表达式,因此v-bind:class接受三目运算
HTML代码:
<div :class="classA ? 'class-a' : 'class-b' ">Demo3</div>
渲染后的HTML:
<div class="class-a">Demo3</div>
v-bind:class 支持对象,对象改变时会动态更新class
HTML代码:
<div :class="{ 'class-a': isA, 'class-b': isB}">Demo4</div>
Javascript代码:
data: {
isA: false, //当isA改变时,将更新class
isB: true //当isB改变时,将更新class
}
渲染后的HTML:
<div class="class-b">Demo4</div>
v-bind:class支持数组, 数组里的变量改变时,会动态更新class列表, 数组中可以包含object类型,数组中的object对象改变,也会更新class列表
HTML代码:
<div :class="[classA, classB]">Demo7</div>
Javascript代码:
data: {
classA: 'class-a',
objectClass: {
classB: 'class-b', // classB 的值为class-b, 则将classB的值添加到class列表
classC: false, // classC值为false,将不添加classC
classD: true // classD 值为true,classC将被直接添加到class列表
}
}
渲染后的HTML:
<div class="class-a class-b classD">Demo7</div>
list.html ( eg:v-bind:class && computed:{} )
<script src="js/vue.js"></script>
<style type="text/css">
.red{
color:red
}
.blue{
color:blue
}
.green{
color:green
}
</style>
</head>
<body>
<div id="box">
<ul>
<li v-for="(item,index) in filterList" v-bind:key='index'>
<input type='checkbox' v-model='item.flag'>
{{item.text}}
</li>
</ul>
<button v-on:click="type='all'">全部</button>
<button v-on:click="type='complete'">完成的</button>
<button v-on:click="type='uncomplete'">未完成的</button>
<input type="text" v-model="n" />{{n}}
<p v-bind:class="[n<60?'red':'',n>85?'blue':'',n>=60 && n<=85?'green':'' ]">{{jg}}</p><!--绑定style中的class选择符,red,blue,green都是类名--> //数组的方法
<!--<p v-bind:class="{'red':n<60,'green':n>85,'blue':n>=60 && n<=85}"> {{jg}}</p>-->//对象的方法
</div>
<script type="text/javascript">
var vm =new Vue({
el:'#box',
computed:{//计算属性
jg(){
if(this.n<60){
return '不及格'
}
else if(this.n>=85){
return '优秀'
}else{
return "及格"
}
},
filterList(){
return this.todos.filter((item)=>{
if(this.type==='all'){
return true
}
else if(this.type==='complete'){
return item.flag
}else{
return !item.flag
}
})
}
},
data:{
todos:[
{text:'zzz',flag:true},
{text:'xxx',flag:false},
{text:'ddd',flag:true}
],
n:'',
type:'all'
}
})
</script>
</body>
三 :component 组件 定义和使用
组件是可复用的 Vue 实例,且带有一个名字
可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用
bootstrap 引入组件 先搜索 bootcdn ---> 找到bootstrap对应的css样式引入到文档 ---->搜索bootstrap ---->中文文档--->components------>找到需要的组件
子组件不能更改父组件传过来的值 因为数据是单向的
格式:
1.定义一个组件名 'one'
2.利用data 数据属性:写函数;
ps: 数据属性data 必须是一个有返回值的函数
3.template 模板:写组件的内容(元素和触发的事件)
4.在创建的Vue根实例中将这个组件作为自定义元素来使用
全局组件
Vue.component("组件的名字",{
template:"模板的内容"
})
局部组件
var 组件的名字 = {
template:"模板的内容"
}
在实例中注册组件
components:{
}
子组件接收父组件传过来的值
props:{ //对象的形式
v:{
type:Number, //数据类型
required:true //指定这个值必须要传,不传就报错
default:50 //默认值 在 父组件没有传值的情况改下就用默认值
}
}
props:[ ]//数组的形式
生命周期函数
created(){ //生命周期的钩子函数,实例被创建之后自动执行代码:
}
全局组件
<div id="box1"><!--这里div 元素(box)就是vue实例的根元素。box就是组件元素one的父元素,要把新建的vue实例绑定在这个父元素中-->
<one></one><!--组件中的模板可以复用,one 就是新建的组件,也就是自定义的元素-->
<one></one>
</div>
<script type="text/javascript">
//全局的组件
Vue.component('one',{ //1.组件名为"one"; 2.data 写函数; 3.template 写组件的内容(元素和触发的事件)
data:function(){//function可以省略不写,数据属性data 必须是一个返回值的函数
return {
msg:'hahaha'
}
},
template:'<div>a component{{msg}}</div>'
//template 是模板的意思,在 html 里面是一个可以同时控制多个子元素的父元素。在这里定义了组件的内容
})
new Vue({
el:'#box1', //需要管理当前div才可以显示出全局组件中的内容
})
</script>
局部组件
//局部组件
<div id="box2">
<my-com><my-com>
</div>
<script>
var myCom={
template:"<div> the component {{msg}}</div>",
data(){//向模板中传值
return{
msg:'hello',
tet:'ssss'
}
}
}
new Vue({
el:'#box2',
components:{//调用组件 注册
myCom:myCom//如果键值名不同 用键名
}
})
<script>
四: 父组件向子组件传值(进度条例子)
progress.html (父组件向子组件传值)
<link href="https://cdn.bootcss.com/twitter-bootstrap/4.1.3/css/bootstrap.css" rel="stylesheet"> //引入的bootstrap样式
<script src="js/vue.js"></script>
<style type="text/css">
.progress{
margin: 10px;
}
</style>
</head>
<body>
<div id="box">
<my-progress v-bind:v='30'></my-progress> <!--父元素通过v向子元素传值-->
<my-progress v-bind:v='60'></my-progress>
<my-progress v-bind:v='90'></my-progress>
</div>
<script type="text/javascript">
var myProgress={
props:['v'],/*子元素接受值*/
template:`<div class="progress">
<div class="progress-bar" role="progressbar" v-bind:#AD0000" >v+'%'}">{{v}}%</div>
</div>`,
}
new Vue({
el:'#box',
components:{
myProgress:myProgress
}
})
</script>
</body>
五 : 子组件向父组件
myprogress.html
<script src="js/vue.js"></script>
<link href="https://cdn.bootcss.com/twitter-bootstrap/4.1.3/css/bootstrap.css" rel="stylesheet">
<style type="text/css">
.progress{
margin:10px;
}
</style>
</head>
<body>
<div id="box">
<my-progress v-bind:v='30' name='one' v-on:child='re' ></my-progress><!--父组件 父组件只是引入了模板中的元素 并不是标签-->
<my-progress v-bind:v='40' name='two' v-on:child='re'></my-progress><!--v-bind:v传给子组件的是一个数值,如果直接v=“30”那么传的是一个字符串-->
<my-progress v-bind:v='70' name='three' v-on:child='re'></my-progress><!--child是事件名 re是事件处理函数-->
<my-progress v-bind:v='90' name='four' v-on:child='re'></my-progress><!--子组件给父组件传值②监听-->
{{msg}}
</div>
<script type="text/javascript">
var myProgress={ //子组件中的操作
/* props:{ //以对象的形式将父组件的值传给子组件
v:{
type:Number, //数据类型
required:true //指定这个值必须要传,不传就报错
default:50 //默认值 在 父组件没有传值的情况改下就用默认值
}
},*/
props:['v','name'],//数组的形式传值 不能有别的限定单纯把v中的值传给子组件 ,name也是父组件中定义的值
created(){ //生命周期的钩子函数,实例被创建之后执行代码
var timer = setInterval(()=>{
this.n++;
if(this.n===100){
clearInterval(timer);
this.$emit('child',this.name);//子组件给父组件传值①发送 进度条加载完成后把值发送给父组件 $emit('事件名','数据')是发送
}
},300)
},
data(){
return{
n:this.v
}
},
template:`<div class="progress"> //子组件
<div class="progress-bar" : >{{n}}%</div>
</div>`
}
new Vue({ //父组件中的操作
el:'#box',
data:{ //将子组件传过来的值接收在这个msg中 渲染到页面上
msg:''
},
components:{
myProgress
},
methods:{ //在父组件的methods里写事件处理的函数,参数是子组件传给父组件的值
re(v){ //③接收 子组件给父组件传值过来的值
this.msg='任务'+v+'已完成';
}
}
})
</script>
</body>
六、兄弟组件之间的传值 (将兄弟组件之间的传值转化为父子组件的传值 son1-->father father---->son2)
add del1.html(子组件给父组件传值-----添加操作)
<link href="https://cdn.bootcss.com/twitter-bootstrap/4.1.3/css/bootstrap.css" rel="stylesheet">
<script src="js/vue.js"></script>
</head>
<body>
<div id="box">
<txt v-on:add='addItem'></txt> //监听到add的时候父元素触发一个addItem函数
</div>
<script type="text/javascript">
var txt ={
template:`<div><input type='text' v-model='txt' v-on:keyup.enter='add'></div>`,//子组件通过add方法把input框中的值发送给父元素
data(){
return{
txt:''//定义txt数据
}
},
methods:{
add(){
this.$emit('add',this.txt) //发送txt的内容
this.txt=''
}
}
}
var vm = new Vue({
el:'#box',
components:{
txt
},
data:{
todoList:[]
},
methods:{
addItem(content){ //将获取到的内容填入todos
this.todoList.push(content)
}
}
})
</script>
</body>
add.del(父组件将从son1处获取到的数据 传给son2-----删除操作)
son1将添加的数据传给父组件,
父组件通过addItem方法将数据添加进todoList,
son2拿到todoList中的所有数据 当点击删除按钮的时候触发del事件,
父组件监听到子组件发送的index 调用removeItem方法 删除父组件中对应的数据。
<body>
<div id="box">
<txt v-on:add='addItem'></txt>
<list v-bind:todolist='todolist' v-on:dell='removeItem'></list>//绑定todoList,从中获取数据
</div>
<script type="text/javascript">
var txt={
template:`<div><input type='text' v-model='txt' @keyup.enter='add' ></div>`,
data(){
return{
txt:''
}
},
methods:{
add(){
this.$emit('add',this.txt)
this.txt=''
}
}
}
var list = {
props:['todolist'],//子组件接收父组件传过来的值
template:`<div>
<ul>
<li v-for='(item,index) in todolist'>{{item}}
<button v-on:click='del'>删除</button> //这里的del是一个方法
</li>
</ul>
</div>`,
methods:{
del(){
this.$emit('dell',this.index)//这里的dell是事件名,并且同时发送下标信息
}
}
}
var vm=new Vue({
el:'#box',
components:{
txt:txt,
list:list
},
data:{
todolist:['aa']
},
methods:{
addItem(content){
this.todolist.push(content);
},
removeItem(index){ //()中的内容就是父组件接收到的信息
this.todolist.splice(index,1)
}
}
})
</script>
</body>
七、动态组件
<component v-bind:is="组件名对应的变量名"></component> //动态组件
<keep-alive> // 可以缓存
dynamic.html(选项卡效果)
<body>
<div id="box">
<button v-on:click="cname='one'">a</button>
<button v-on:click="cname='two'">b</button>
<keep-alive> <!--缓存组件中的内容-->
<component v-bind:is='cname'></component><!--cname是变量名-->
</keep-alive>
</div>
<script type="text/javascript">
var one = {
template:`<div>aaaa
<input type='text' > //缓存后即使点了别的选项再次点回这个选项时input框中的内容也依然在
</div>`
}
var two = {
template:`<div>bbbb</div>`
}
var vm = new Vue({
el:'#box',
data:{
cname:'one' //默认是one中的内容 如果不写就不显示任何内容 cname是变量名 one是组件名
},
components:{
one,two
}
})
</script>
</body>
封装一个tab选项卡
<body>
<div id="box">
<tab :title="['a','b','c']" :content="['aaaa','bbbb','cccc']"></tab>
</div>
<script type="text/javascript">
var tab = {
props:['title','content'],
created(){
this.arr=this.content.map((item)=>{// 用map方法将content中的每个元素转为组件
return{
template:`<div>${item}</div>`
//template中定义的就是子组件 ES6中的变量要保存在${}中
}
})
},
template:`<div>
<ul>
<li v-for='(item,idx) in title' v-on:click="index=idx" >{{item}}</li>
</ul>
<component v-bind:is="arr[index]"></component>
//arr[index]代表的是组件
</div>`,
data(){
return{
arr:[],//存放的组件,每个元素都是组件
index:0
}
}
}
var vm = new Vue({
el:'#box',
components:{
tab
}
})
</script>
</body>