引子:什么是前后端分离和前后端不分离?
前后端分离指的是后端开发人员只负责用来书写后端逻辑代码,不用再去管前端页面的搭建,前端人员只负责做好前端页面效果,不用管数据,数据直接向后端人员要,后端和前端通过路由接口来实现数据的传递,vue就是前后端用来交互使用的一个前端框架,那我们这边后端先是用的django,后续会使用其他框架,比如Flask,Tornado等。前端主流框架有三种,vue只是其中的一种,还有两种分别是Angular,React。
前后端不分离指的是所有后端代码和前端页面的搭建都由你自己完成,比如django框架就可以实现前后端不分离,后端书写代码,开路由,提供数据,前端访问路由,拿数据,渲染页面。render,redirect,Jsonponse等携带数据给前端,这种就是完全的前后端不分离设计,好处是所有的代码都是自己写的,不用和前端人员进行交互,避免由于一些外见因素影响整个项目的走向,坏处是可拓展性不高,牵一发而动全身!
注意:在前后端分离的项目中使用django,一般我们都需要将csrfmiddlewaretoken中间件注释掉,因为这个东西是django自己带的安全认证,其他的东西都走不了,但是前后端不分离就没有必要了。
vue介绍
什么是vue?
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
所谓的渐进性指的就是一个页面小到一个变量,大到整个页面,均可以由vue控制,vue也可以控制整个项目。
思考:vue如何做到一次引入控制整个项目==》单页面应用==》vue基于组件的开发
学习曲线:vue的指令 vue的实例成员 vue组件 vue项目开发
vue的特点是什么?
1.单页面:高效
2.虚拟DOM:页面缓存
3.数据的双向绑定:数据是具有监听机制
4.数据驱动:从数据出发,不是从DOM出发
vue的下载使用
1.下载vue.js:https://vuejs.org/js/vue.js
2.在要使用vue的html页面通过script标签引入
3.在html中书写挂载点的页面结构,用id表示
4.在自定义的script标签实例化vue对象,传入一个大字典
5.在字典中通过el与挂载点页面结构绑定,data为其传输数据
vue的基本语法
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>vue初识</title> </head> <body> <div id="app"> <!-- {{ vue变量 }} 插值表达式 --> <h1>{{ h1_msg }}</h1> <h2>{{ h2_msg }}</h2> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', // 挂载点 data: { // 为挂载点的页面结构提供数据 h1_msg: 'h1的内容', h2_msg: 'h2的内容', } }) </script> </html>
vue完成简单的事件
<div id="app"> <h1 v-on:click="clickAction">h1的内容是{{ msg }}</h1> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { msg: 'vue渲染的内容' }, methods: { // 为挂载点提供事件的 clickAction: function () { alert(123) } } }) </script>
vue操作简单的样式
<div id="app"> <p v-on:click="btnClick" v-bind:style="v_style">点击p文字颜色变为绿色</p> <div v-on:click="btnClick" v-bind:style="v_style">点击div文字颜色变为绿色</div> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { v_style: { color: 'black' } }, methods: { btnClick: function () { this.v_style.color = 'green' } } }) </script>
总结:1.vue是通过v-*指令来控制标签的
2.vue通过变量data来驱动页面
vue学习之指令
vue的指令主要有文本指令,事件指令,属性指令,条件指令,循环指令,其中vue的指令都是以v-*开头的,下面来一一学习。
文本指令
<!-- 插值表达式就是 v-text --> <p>{{ msg1 }}</p> <p v-text="msg2"></p> <!-- 可以解析html标签 --> <p v-html="msg3"></p> <!-- 必须赋初值,渲染的结果永远不会发生改变 --> <p v-once="msg3" v-on:mouseover="action">{{ msg3 }}</p>
示例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <div id="app01"> <!--插值表达式就是 v-text--> <p>{{ msg1 }}</p> <p v-text="msg2"></p> <p v-html="msg3"></p> <p v-once="msg3" v-on:mouseover="action">{{ msg3 }}</p> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el:'#app01', data:{ msg1:'ni hao ma ', msg2:'<b>**msg2**</b>>', msg3:'<b>**msg3**</b>>' }, methods:{ action:function () { this.msg3='<i>**new msg3</i>' } } }) </script> </html>
事件指令
<!-- v-on:事件名="函数名" 可以简写为 @事件名="函数名" (v-on: => @)--> <p v-on:click="action1">{{ msgs[0] }}</p> <p @click="action2">{{ msgs[1] }}</p>
我们如何做到区分到底是哪个事件被触发了呢?那就得通过一个东西告诉我这个事件被触发了,这个时候我们就可以通过事件的传参来解决这个问题
<!--事件的传参 一旦传参了就可以区别了--> <ul> <li @click="liAction(100)">列表项1</li> <li @click="liAction(200)">列表项2</li> <li @click="liAction(300)">列表项3</li> </ul>
鼠标事件我们可以用来检测鼠标的位置,他在传参的过程中就是默认将鼠标对象传入,然后直接书写函数名,但是注意,一旦给鼠标事件传参了就不会触发本身的鼠标事件了,如果还想看到鼠标事件,就得用到了$event
<!-- 鼠标事件的对象:直接写函数名,默认将鼠标事件对象传入 --> <div @click="func1">func1</div> <!-- 鼠标事件的对象:一旦添加(),就必须手动传参,$event就代表鼠标事件对象 --> <div @click="func2($event, 'abc')">func2</div>
示例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <div id="app01"> <!--v-on:事件名=‘函数名’ 可以简写为@事件名=‘函数名’ (v-on:=>@)--> <p v-on:click="action">{{ msg[0] }}</p> <p @click="action2">{{ msg[1] }}</p> <!--事件的传参 一旦传参了就可以区别了--> <ul> <li @click="liAction(100)">列表项1</li> <li @click="liAction(200)">列表项2</li> <li @click="liAction(300)">列表项3</li> </ul> <!--鼠标事件的对象:直接写函数名,默认将鼠标事件对象传入--> <div @click="func1">func1</div> <!--模拟鼠标的位置,可以拿到具体的鼠标的位置--> <p @click="msg2()">msg</p> <!--一旦你接受参数了,那么就不会触发到鼠标的点击事件,拿到的就是你传参的值--> <!--事件的鼠标对象,想传参数又想要鼠标对象本身,那就$event--> <p @click="func2($event,67)">func2</p> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el:'#app01', data:{ // 这个里面写的是标签外面的东西,也就是展示给用户看的数据 msg:['111111','222222'] }, methods:{ //这个里面写的都是所有在标签里面的东西,这个里面的东西都要靠数据才能支撑的起来 action:function () { alert(this.msg[0]) }, action2:function () { alert(this.msg[1]) }, liAction:function (num,msg) { //传参过来但是接不接收是你的事 //alert('你丫点我了') //成功谁点谁就弹出谁,怎么区分到底是谁点我了,那就传参 console.log(num,msg) }, func1:function (ev) { console.log(ev) }, msg2:function (ev) { console.log(ev) }, func2:function (ev,num) { console.log(ev); console.log(num) } }, }) </script> </html>
属性指令
所谓的属性指令,就是标签里面的属性,除了标签自带的属性,比如class,style外,还包括自定义的属性,比如name='mcc',age='18',还有的onclick等也是属性,但是由于具有特殊性,我们将它分为了事件指令。
语法
# 属性指令 <p v-bind:style="{ fontSize:fs,color: c}"></p> # 简写为 <p class='rDiv' :style="{ fontSize:fs,color: c} " >2345</p>
具体解释
<!--语法:v-bind:属性名=“变量” (v-bind:可以简写为:)--> <p class="" style="" owen="oo" :jason="jj"></p> <!--class属性--> <p :class="c1" @click="action1"></p> <!--给c1是为了让这个东西后面可以变化,不然就是写死了--> <!--双类名--> <!--'br'固定写死的数据,不再是变量--> <p :class="[c1,c2]"></p> <!--style--> <!--一个变量:该变量值为{},{}内部完成一一个个的属性的设置--> <p class='rDiv' :style="s1">1234</p>
除了上面的这种方式外,我们还可以通过字典控制这个属性
<!--一个{},{}内一个个属性有一个个变量单独控制--> <p class='rDiv' :style="{ fontSize:fs,color: c} " >2345</p>
示例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> <style> .rDiv{ width: 100px; height: 100px; background-color: red; } .gDiv{ width: 100px; height: 50px; background-color: green; border-radius: 50%; } .br{ border-radius: 50%; } br </style> </head> <body> <div id="app01"> <!--什么是属性 class,style,,onclick,--> <!--onclick, 事件指令--> <!--owen 自定义属性--> <!--属性指令,用vue绑定属性,将属性内容交给vue处理--> <!--属性指令:用vue绑定属性,将属性内容交给vue处理--> <!--语法:v-bind:属性名=“变量” (v-bind:可以简写为:)--> <p class="" style="" owen="oo" :jason="jj"></p> <!--class属性--> <p :class="c1" @click="action1"></p> <!--给c1是为了让这个东西后面可以变化,不然就是写死了--> <!--双类名--> <!--'br'固定写死的数据,不再是变量--> <p :class="[c1,c2]"></p> <!--style--> <!--一个变量:该变量值为{},{}内部完成一一个个的属性的设置--> <p class='rDiv' :style="s1">1234</p> <!--一个{},{}内一个个属性有一个个变量单独控制--> <p class='rDiv' :style="{ fontSize:fs,color: c} " >2345</p> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el:'#app01', data:{ oo:'owen', jj:'jason', c1:'rDiv', c2:'br', s1:{ //'font-size':'30px' fontSize:'30px', color:'green' }, fs:'20px', c:'black' }, methods:{ action1:function () { if(this.c1=='rDiv'){ this.c1='gDiv' }else{ this.c1='rDiv' } } } }) </script> </html>
条件指令
<!-- 条件指令 v-show | v-if--> <!-- v-show:消失是以 display: none渲染 --> <div class="div" v-show="s1"></div> <div class="div" v-show="s1"></div> <!-- v-if:消失时不会被渲染渲染,所以建议建立缓存, 用key属性 --> <div class="div" v-if="s2" key="div1"></div> <div class="div" v-if="s2" key="div2"></div>
v-if 需要我们建立缓存,这样子就可以加速切换,vue页面的切换其实就是组件的切换,组件的切换之间也是通过缓存,也就是虚拟DOM
示例
<meta charset="UTF-8"> <style> .div { width: 100px; height: 100px; background-color: greenyellow; border-radius: 50%; } </style> <div id="app"> <!-- 条件指令 v-show | v-if--> <!-- v-show:消失是以 display: none渲染 --> <div class="div" v-show="s1"></div> <div class="div" v-show="s1"></div> <!-- v-if:消失时不会被渲染渲染,所以建议建立缓存, 用key属性 --> <div class="div" v-if="s2" key="div1"></div> <div class="div" v-if="s2" key="div2"></div> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { s1: false, // s2: false 没写默认为false } }) </script>
小事例
<meta charset="utf-8"> <style> ul li { border: 1px solid black; width: 60px; float: left; } ul { list-style: none; } ul:after { content: ""; display: block; clear: both; } .wrap { width: 500px; height: 200px; } .red { background-color: red; } .blue { background-color: blue; } .green { background-color: green; } </style> <div id="app"> <!-- v-if v-else-if v-else 案例 --> <ul> <li @click="changeWrap(0)">red</li> <li @click="changeWrap(1)">green</li> <li @click="changeWrap(2)">blue</li> </ul> <!-- red页面逻辑结构 --> <div class="wrap red" v-if="tag == 0" key="aaa"></div> <!-- green页面逻辑结构 --> <div class="wrap green" v-else-if="tag == 1" key="bbb"></div> <!-- blue页面逻辑结构 --> <div class="wrap blue" v-else key="ccc"></div> <!-- v-if相关分支操作,在未显示情况下,是不会被渲染到页面中 --> <!-- 通过key全局属性操作后,渲染过的分支会建立key对应的缓存,提高下一次渲染速度 --> </div> <script src="js/vue.js"></script> <script type="text/javascript"> new Vue({ el: "#app", data: { tag: 0, }, methods: { changeWrap (num) { this.tag = num; } } }) </script>
v-if补充
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <div id="app01"> <p v-if="r1" key="p_r1">if 条件</p> <p v-show="r2">show 条件</p> {{ num + 1 -5 * 2 + '好的' }} <ul> <!--v-else默认与v-if等有条件的分支绑定--> <!--v-else-if必须有条件才和有条件v-if分支绑定--> <li v-if="tag==1">111</li> <li v-else-if="tag==2">222</li> <li v-else="">333</li> </ul> <ul> <!--v-else默认与v-if等有条件的分支绑定--> <!--v-else-if必须有条件才和有条件v-if分支绑定--> <li @click="action(1)">a</li> <li @click="action(b)">b</li> <li @click="action(c)">c</li> </ul> <ul> <!--v-else默认与v-if等有条件的分支绑定--> <!--v-else-if必须有条件才和有条件v-if分支绑定--> <li v-show="flag==1">aaa</li> <li v-show="flag==b">bbb</li> <li v-show="flag==c">ccc</li> </ul> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el:'#app01', data:{ num:10, r1:true, r2:false, tag:2, flag:'a' }, methods:{ action:function (msg) { this.flag=msg } } }) </script> </html>
循环指令
循环指令主要是for循环,使用也是v-for,但是和python稍微有点区别的是对于列表来说,第一个元素是列表里面的元素,第二个才是索引,对于字典来说,第一个是value值,第二个是key值,第三个是索引。
<p>{{nums[2]}}</p> <!--for循环遍历列表--> <ul> <li v-for="num in nums">{{ num }}</li> </ul> <!--for循环的参数第一个是值,第二个是索引--> <ul> <li v-for="(num,index) in nums">{{ num }}{{ index }}</li> </ul> <!--for循环遍历字典取到的第一个值是value值--> <ul> <li v-for="num in people">{{ num }}</li> </ul> <!--for循环遍历字典取到的第二个值是key值,第三个是索引--> <ul> <li v-for="(num,index,age) in people">{{ num }}{{ index }}{{ age }}</li> </ul>
事列
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <div id="app01"> <p>{{nums[2]}}</p> <!--for循环遍历列表--> <ul> <li v-for="num in nums">{{ num }}</li> </ul> <!--for循环的参数第一个是值,第二个是索引--> <ul> <li v-for="(num,index) in nums">{{ num }}{{ index }}</li> </ul> <!--for循环遍历字典取到的第一个值是value值--> <ul> <li v-for="num in people">{{ num }}</li> </ul> <!--for循环遍历字典取到的第二个值是key值,第三个是索引--> <ul> <li v-for="(num,index,age) in people">{{ num }}{{ index }}{{ age }}</li> </ul> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el:'#app01', data:{ nums:['111','222','333'], people:{ 'name':'owen', 'age':18, 'sex':'male' } }, }) </script> </html>
解决插值表达式冲突的问题
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <div id="app01"> <p> {{msg}} </p> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el:'#app01', data:{ msg:'12345' }, delimiters:['${','}'] //存在的主要是和django的模板层进行区分 }) </script> </html>
vue之10行代码搞定评论楼
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <div id="app01"> <p> <input type="text" v-model="val"> <button @click="add">submit</button> </p> <!--添加评论--> <ul> <li v-for="(info,i) in infos">{{ info }} <span @click="del(i)">x</span> </li> </ul> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el:'#app01', data:{ infos:[], //用来存放评论相关 val:'', //用来获取input框的内容 }, methods:{ add:function () { let vals = this.val; if(vals){ this.infos.splice(0,0,vals); this.val='' } }, del:function (i) { this.infos.splice(i,1) } } }) </script> </html>
vue成员之computed
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <div id="app01"> <p> 姓:<input type="text" v-model="first_name"> 名:<input type="text" v-model="last_name"> </p> <p> 姓名:<b>{{full_name}}</b> </p> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el:'#app01', data:{ //full_name:'None', 用来显示两个数的和 first_name:'', last_name:'' }, computed:{ //想让两个数据和起来,那就用来做加法运算 那就是函数 full_name:function () { //此处的this指的就是这个实例 return this.first_name + this.last_name //+ // return this.first_name - this.last_name - // return this.first_name * this.last_name * // return this.first_name / this.last_name / // return this.first_name ** this.last_name ** } } }) </script> </html>
虽然computed可以帮我们完成加减乘除,但是我们要知道的是computed的作用并不是这个,他最主要的是可以帮我们做监听事件,定义在函数里面的所有变量都会处于一个实时被监听的状态,他的返回值可以随意的返回,而且他绑定的变量不可以在data中书写,目前不支持!
vue成员之watch
computed是监听函数里面的变量,但是现在我们想要的是监听绑定函数的这个变量,怎么做呢?需要我们用到watch方法。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <div id="app01"> <p> 姓名:<input type="text" v-model="full_name"/> </p> <p> 姓:<b>{{first_name}}</b> <!--姓:<input type="text" v-model="first_name"/>--> 名:<b>{{last_name}}</b> </p> </div> </body> <script src="js/vue.js"></script> <script > new Vue({ el:'#app01', data:{ full_name:'', last_name:'', first_name:'' }, watch:{ full_name:function () { let res = this.full_name.split(''); this.first_name = res[0]; this.last_name = res[1] } } }) </script> </html>
watch方法可以用来监听我们绑定函数的这个变量,而且这个变量可以在data中定义,这样的话,我们就可以达到了即能监听函数里面的变量,也可以监听函数外面的绑定函数的变量。这个函数里面的东西对于我们监听来说完全无所谓,我们要的是监听外面的变量。
然后我们可以通过对这个的监听完成字符串的切分,注意在后端我们不可以使用空字符串切分,但是前端支持,但是前端不支持解压赋值哦,you can try!
组件
什么是组件?
组件就是一个个的vue实例,也可以说一个vue实例就是一个组件,是HTML模板,css样式,js逻辑的集合体。
-
每个组件均具有自身的模板template,根组件的模板就是挂载点
-
每个组件模板只能拥有一个根标签
-
子组件的数据具有作用域,以达到组件的复用
使用vue时,实际项目中大多使用局部组件。局部组件与全局组件都拥有各自的名称空间,这是通过将成员data的值赋予一个return 字典 的的function来实现的。
组件的书写
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <!--有html模板,有CSS样式,有js逻辑的集合体--> <div id="app01"> <!--挂载点不要用html,也不要用body,因为会被组件替换掉--> <p> <h1>组件的概念</h1> </p> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el:'#app01', // template: '<div>' + // '<h1>组件渲染的模板</h1>' + // '</div>', //在这里写组件,挂载点被替换掉了 //直接这样子并不能书写多行,如果想要书写多行的话,那就得用到了反引号 template:` <div> <h1>组件渲染的模板</h1> <span>我们一定会在一起</span> </div> `, data:{ }, methods:{ } }) </script> </html>
如果想要给当前这个组件添加样式,我们有两种方法,第一种是直接在标签内部书写,还有一种是在head里面书写,因为我们目前是在一个html模板中,所以可以这么做!
第一种方法 <style> span{ color: yellowgreen; } </style> </head> 第二种方法 template:` <div style="color: red"> <h1>组件渲染的模板</h1> </div>
`
组件的最终格式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> <style> span{ color: yellowgreen; } </style> </head> <body> <!--有html模板,有CSS样式,有js逻辑的集合体--> <div id="app01"> <!--挂载点不要用html,也不要用body,因为会被组件替换掉--> <p> <h1>组件的概念</h1> </p> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el:'#app01', template:` <div style="color: red"> css样式 <h1>组件渲染的模板</h1> <span @click="lll">我们一定会在一起</span> </div> `, data:{ }, methods:{ lll:function () { //js逻辑 alert(123) } } }) </script> </html>
这就是组件的最终格式,有自己的HTML模板,有css样式,还有自己的js逻辑的代码块,然后我们在实际开发中肯定会有好多好多的组件,这就需要用到了全局子组件和局部子组件,然后我们的template只在局部组件中使用,根组件直接使用挂载点的模板就好。
局部组件
注意在使用局部组件的时候一定要注册,在components中
每个组件模板只能拥有一个根标签
写错了,是只可以有一个根标签,这里的根标签就是div,如果你再给一个h2,就是有两个根标签了!
子组件的数据具有作用域,以达到组件的复用
作用域是什么,就是每一个组件都有自己的名称空间,用来处理自己的数据,比如
这个时候我们就发现了组件的作用域的好处了,怎么做?想想我们知道的还有名称空间的的东西都有哪些?
函数,类,模块,还有呢?好像没了吧,那就只能在这几个中挑选一个咯,函数最简单了,就你了!
data:function(){
return {
count:0
}
},
这里这么写的原因是
1.我们需要一个名称空间,来返回自己的数据
2.data要求返回的是一个字典
所以最终我们返回的是这种格式,在return的时候返回的是一个字典
然后我们要绑定点击事件,谁点击就加1,那就绑定点击事件,绑定完成之后,我们要用到methods来做这个事件,但是注意,你的methods是放在组件自己的名称空间呢?还是放在根组件的名称空间呢? 那必须是自己的,不然你的数据怎么不一致!
代码展示
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <div id="app01"> <abc></abc> <abc></abc> </div> </body> <script src="js/vue.js"></script> <script> //定义局部组件 <!--组件最大的作用就是让html代码块具有复用性--> let localTag={ data:function(){ return { count:0 } }, template:` <div class="box" style="border: solid; 100px"> <h2>标题</h2> <p class="p1">文本内容</p> <p @click="action" class="p2" style="background-color: yellowgreen" >被点击了{{ count }}下</p> </div> `, methods:{ action:function () { this.count++ } } }; //如何注册 new Vue({ el:'#app01', data:{ }, components:{ //components!!!!!!,还有一个component ,效果完全不出来! 'abc':localTag }, }) </script> </html>
全局组件
基本格式
<script> <!--格式--> Vue.component('全局组件名',{ 在该字典中书写代码块 });
代码展示
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <div id="app01"> <aaa></aaa> </div> </body> <script src="js/vue.js"></script> <script> // <!--格式--> // Vue.component('全局组件名',{ // 在该字典中书写代码块 // }); Vue.component('aaa',{ data:function(){ return { count:0 } }, template:` <div class="box" style="border: solid; 100px"> <h2>标题</h2> <p class="p1">文本内容</p> <p @click="action" class="p2" style="background-color: yellowgreen" >被点击了{{ count }}下</p> </div> `, methods:{ action:function () { this.count++ } } }); new Vue({ el:'#app01', data:{ }, }) </script> </html>
注意,全局组件与局部组件的区别是全局组件不需要注册,局部组件需要注册,我们自己在使用的时候,用全局组件会多一些,但是在一个项目 开发中使用局部组件会多!
知道了组件之后,我们实际中会有多个组件存在,多个组件中拿到的数据有可能是从根组件提供的,如何从根组件那里拿到数据,或者说从子组件那里拿到数据给根组件,这就是组件之间的信息交互,和我们学过的进程间通信是比较像的,我们下面来学习书写
组件信息交互
信息的交互分为父传子和子传父,具体代码如下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <div id="app01"> <!--两者之间的联系点就在这里,msg在父标签中定义,然后给了Owen--> <abc :owen="msg"></abc> <!--<localTag></localTag>--> </div> </body> <script src="js/vue.js"></script> <script> // 这个是自定义的局部组件 let localTag={ //我们这里通过反射取到了msg,将msg传给下面的span标签 props:['owen'], template:` <div> <h2>组件间信息交互</h2> <span>{{ owen }}</span> </div> ` }; //vue实例 new Vue({ el:'#app01', data:{ msg:'父级的信息' }, components:{ //'abc':localTag 'abc':localTag } }) </script> </html>
父传子重点就是找对信息交互的点,通过反射将这个值取出就好
子传父
父级先产生,然后加载子级,父级产生的信息传给子级,子级完成了一系列的数据操作之后传给父级,那就是钩子思想的运用,在子级定义一个事件,只要触发了就传给父级。
全局组件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> </head> <body> <div id="app01"> <h1>{{ title }}</h1> <!--传过来的参数在这里接收,这个就是连接两个组件的中间点--> <global-tag @recv="get_title"></global-tag> </div> </body> <script src="js/vue.js"></script> <script> Vue.component('global-tag',{ template:` <div> <input type="text" v-model="msg"> <button @click="action">修改标题</button> </div> `, data:function(){ return{ msg:'' } }, methods:{ action:function () { let mss = this.msg; // 一定要有监听机制 ,第一个是事件,第二个是你要传的参数 this.$emit('recv',mss) } } }); new Vue({ el:'#app01', data:{ title:'父组件定义的标题' }, methods:{ //接受完以后,就要修改标题了 get_title:function (msg) { this.title = msg } } }) </script> </html>
重点理解一下,稍稍有点绕,绕明白就好了,想不明白私我。