##1、走进Vue
#1、what -- 什么是Vue 渐进式 JavaScript 框架、可以独立完成前后端分离式web项目的JavaScript框架 #2、why -- 为什么要学习Vue 三大主流框架之一:Angular React Vue 先进的前端设计模式:MVVM 可以完全脱离服务器端,以前端代码复用的方式渲染整个页面:组件化开发 #3、special -- 特点 1)单页面 - 硬件要求低 2)组件化开发 3)数据驱动 4)数据的双向绑定 5)虚拟DOM 6)轻量级 #4、how -- 如何使用Vue - 开发版本:[vue.js](https://vuejs.org/js/vue.js) - 生产版本:[vue.min.js] <div id="app"> {{ }} </div> <script src="js/vue.min.js"></script> //下载到本引入vue <script> new Vue({ el: '#app' }) </script>
##2、Vue实例
##2-1、el实例
new Vue({ el: '#app' }) // 实例与页面挂载点一一对应 // 一个页面中可以出现多个实例对应多个挂载点 // 实例只操作挂载点内部内容
##2-2、data数据
<div id='app'> {{ msg }} </div> <script> var app = new Vue({ el: '#app', data: { msg: '数据', } }) console.log(app.$data.msg); console.log(app.msg); </script> <!-- data为插件表达式中的变量提供数据 --> <!-- data中的数据可以通过Vue实例直接或间接访问-->
##2-3、methods 方法
<style> .box { background-color: orange } </style> <div id='app'> <p class="box" v-on:click="pClick">测试</p> <p class="box" v-on:mouseover="pOver">测试</p> </div> <script> var app = new Vue({ el: '#app', methods: { pClick () { // 点击测试 }, pOver () { // 悬浮测试 } } }) </script> <!-- 了解v-on:为事件绑定的指令 --> <!-- methods为事件提供实现体-->
##2-4、computed 计算属性
<!DOCTYPEhtml><html><head><metacharset="utf-8"><title>监听多个变量</title></head><body><divid="app"><inputtype="text"v-model="a_val"><inputtype="text"v-model="b_val"><inputtype="text"v-model="c_val"><p>{{val_fn}}</p></div></body><scriptsrc="js/vue.js"></script><script>newVue({el:'#app',data:{a_val:'',b_val:'',c_val:'',},//computed内部书写方法-管理可以监听多个变量的方法//1)方法名可以直接作为变量被渲染,值为方法的返回值//2)在方法名被渲染后(在页面中使用了),方法内部的所有变量都会被监听//3)computed用来解决一个变量值依赖一个或多个变量值computed:{val_fn(){//this.a_val;//this.b_val;//this.c_val;console.log('该方法被调用了');returnthis.a_val+this.b_val+this.c_val;}}})</script></html>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div id="app"> <p> 姓:<input type="text" v-model="last_name"> </p> <p> 名:<input type="text" v-model="first_name"> </p> <p> 姓名:{{ full_name }} </p> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { last_name: '', first_name: '', }, computed: { full_name () { return this.last_name + ' ' + this.first_name; } } }) </script> </html>
##2-5、watch 监听属性
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>监听属性</title> </head> <body> <div id="app"> <p> 姓名:<input type="text" v-model="full_name"> </p> <p> 姓:<input type="text" v-model="last_name"> </p> <p> 名:<input type="text" v-model="first_name"> </p> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { full_name: '', last_name: '', first_name: '', }, // watch内部书写方法 - 管理 监听绑定的属性(提前要存在) 的方法 // 1)方法名 被监听的变量名(属性) // 2) 在方法名被渲染后,方法名代表的属性值改变,绑定的方法就会被调用 // 3)watch用来解决多个变量值依赖一个变量值 watch: { full_name () { console.log('被调用了'); // full_name变量值改变,要完成的任何逻辑都可以书写在此方法中 let name = this.full_name.split(' '); this.last_name = name[0]; this.first_name = name[1]; } } }) </script> </html>
##2-6、delimiters 分隔符
<div id='app'> ${ msg } //修改后的分隔符 </div> <script> new Vue({ el: '#app', data: { msg: 'message' }, delimiters: ['${', '}'] }) </script>
##3、生命周期钩子
表示一个vue实例从创建到销毁的这个过程,将这个过程的一些时间节点赋予了对应的钩子函数 钩子函数: 满足特点条件被回调的方法 #重点掌握两个方法 created mounted #vue api 链接 生命周期 https://cn.vuejs.org/v2/api/#%E9%80%89%E9%A1%B9-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E9%92%A9%E5%AD%90 #生命周期图示: 可直接查看官网
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>vue组件的生命周期钩子</title> </head> <body> <div id="app"> <h1>一个vue组件从创建到销毁整个生命周期过程中一些时间节点回调的方法</h1> <local-tag></local-tag> </div> </body> <script src="js/vue.js"></script> <script> let localTag = { template: ` <div> <h2 @click="btnClick">{{ msg }}</h2> </div> `, data () { return { msg: '局部组件', x: 'x', y: 'y' } }, methods: { btnClick () { console.log(this.msg) }, zzz() {} }, beforeCreate () { console.log('组件开始创建,数据和事件都为创建'); console.log(this.msg); console.log(this.btnClick); console.log(this.$data); }, pppp: [1, 2, 3], created () { console.log('组件已经创建完毕,数据与事件都准备就绪'); console.log(this.msg); console.log(this.btnClick); console.log(this.$data); console.log(this.$options.methods); console.log(this.$options.pppp); }, }; new Vue({ el: '#app', components: { localTag, } }) </script> </html>
##4、Vue指令
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>文本指令</title> </head> <body> <div id="app"> <!--1、插值表达式:在内部直接写变量或变量表达式--> <p>{{ msg }}</p> <p>{{ (num + 1 - 3) / 2 }}</p> <!--2、v-text v-html v-once 三个文本指令 --> <!--v-text:纯文本--> <p v-text="msg"></p> <!--v-html:可以解析标签--> <p v-html="'<b>加粗文本</b>'"></p> <p v-html="htmlMSG" @click="changeMsg"></p> <!--v-once:插值表达式渲染文本,once来限制文本不可修改--> <!--插值表达式中一个变量被限制,整个结果都被限制--> <p v-once="htmlMSG">{{ htmlMSG + msg }}</p> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { msg: 'message', num: 10, htmlMSG: '<b>加粗文本</b>' }, methods: { changeMsg: function () { this.htmlMSG = '<i>加粗文本</i>'; this.msg = '11111111111111'; } } }) </script> </html>
<style type="text/css"> [v-cloak] { display: none; } </style> <div id="app" v-cloak> {{ msg }} </div> <script src="js/vue.min.js"></script> <script type="text/javascript"> new Vue({ el: "#app", data: { msg: "message" } }) </script> <!-- 避免页面闪烁-->
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>事件指令</title> <style> [aaa*='2'] { color: red; } [v-cloak] { display: none; } </style> </head> <body> <div id="app" v-cloak aaa="123"> <!-- v-on指令: 1)明确事件名 2)明确事件函数 v-on:事件名="事件函数" --> <!--1、基础的事件绑定--> <p v-on:click="clickAction">单击</p> <p v-on:dblclick="dblclickAction">双击</p> <!--2、绑定事件并传参--> <ul> <li v-on:click="liAction(0)">{{ li1 }}</li> <li v-on:click="liAction(1)">222</li> <li v-on:click="liAction(2)">333</li> </ul> <!--3、传递事件对象--> <p v-on:click="sysAction1">不传自定义参数</p> <p v-on:click="sysAction2(888, $event)">传自定义参数</p> <!--4、v-on: 可以简写为 @ --> <p @click="clickAction">单击</p> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { li1: '111' }, methods: { clickAction: function () { alert('点击') }, dblclickAction () { alert('双击') }, liAction (index) { // alert('li被点击了'); // alert(this.li1); alert(index); }, sysAction1 (ev) { console.log(ev) }, sysAction2 (num, ev) { console.log(num); console.log(ev); } } }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>属性指令</title> <style> .box { 200px; height: 200px; background-color: orange; } .wrap { 100px; height: 100px; background-color: red; } .kiss { 150px; height: 150px; background-color: cyan; } .x { 300px; } .y { height: 300px; } .z { background-color: brown; } </style> </head> <body> <div id="app"> <!-- v-bind属性指令 :属性名="属性变量",v-bind: 可以简写为: --> <!--eg: v-bind:class='myClass' | v-bind:style='myStyle' | v-bind:aaa='myAAA' --> <div class="box" v-bind:style="myStyle" @click="changeColor('pink')"></div> <!--1、操作单个样式:w变量的值就是为属性宽提供数据的--> <div class="box" v-bind:style="{'width': w}" @click="changeWidth"></div> <!--2、操作多个样式: more_style是一个对象变量,可以赋值多个key:value样式--> <div class="box" v-bind:style="more_style" @click="changeStyle"></div> <!--3、v-bind: 可以简写为 :,可以绑定所有系统和自定义属性,属性一旦绑定,后方就是变量 --> <div :aaa="AAA">简写v-bind</div> <!--4、操作单个类名--> <!--直接赋值:c1就是变量,变量的值就是类名--> <div :class="c1" @click="changeClass"></div> <!--布尔切换:该div有一个kiss类名,kiss_able的true或false决定kiss是否生效--> <div :class="{kiss: kiss_able}"></div> <!--5、操作多个类名: [变量1, ..., 变量n] 每个变量的值都是该标签的类名 --> <div :class="[x, y, {z: is_z}]"></div> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { myStyle: 'background-color: red;', w: '400px', more_style: { '100px', height: '100px', borderRadius: '50%', backgroundColor: 'cyan' }, AAA: 'BBB', c1: 'wrap', kiss_able: true, x: 'x', y: 'y', // z: 'z', is_z: true }, methods: { changeColor (color) { this.myStyle = 'background-color: ' + color + ';' }, changeWidth () { this.w = '500px' }, changeStyle () { this.more_style.borderRadius = '30%' // this.more_style = { // '200px', // height: '200px', // borderRadius: '50%', // backgroundColor: 'tan' // } }, changeClass () { if (this.c1 === 'box') { this.c1 = 'wrap'; } else { this.c1 = 'box'; } // 布尔类型值来回切换 this.kiss_able = !this.kiss_able; } } }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div id="app"> <!-- v-model 表单指令 v-model="变量" 变量给value属性提供值 --> <!--1、数据的双向绑定--> <input type="text" v-model="val"> <input type="text" v-model="val"> <p>{{ val }}</p> <form action=""> <!--2、普通输入框: 直接绑定变量即可 --> <input type="password" v-model="val"> <!--3、单选框--> <!--radio_val的值是多个单选框中一个的value值,代表该单选框默认选中--> <p> <label for="male">男</label> <input id="male" type="radio" value="male" v-model="radio_val" name="sex"> <label for="female">女</label> <input id="female" type="radio" value="female" v-model="radio_val" name="sex"> <button @click="alertValue">单选框提交给后台的value</button> <span>{{ radio_val + '被选中' }}</span> </p> <!--4、独立使用的复选框 --> <!--sure_val的值为true|false,决定该单个复选框是否选中--> <p> <input type="checkbox" name="sure" value="同意" v-model="sure_val"> <span>{{ sure_val }}</span> </p> request.GET.get('sure', None) <!--5、复选框--> <!--hobby_val的值是数组,里面用来存放复选框所有选项的值,值存在代表该选框选中--> <p> 男<input type="checkbox" value="male" name="hobby" v-model="hobby_val"> 女<input type="checkbox" value="female" name="hobby" v-model="hobby_val"> 哇塞<input type="checkbox" value="?" name="hobby" v-model="hobby_val"> <span>{{ hobby_val }}</span> </p> <p> <input type="submit"> </p> </form> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { val: '', radio_val: 'male', sure_val: true, hobby_val: ['?', 'male'] }, methods: { alertValue () { alert(this.radio_val) } } }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style> [v-cloak] { display: none; } .box { 200px; height: 200px; } .b1 {background-color: orange;} .b2 {background-color: cyan;} .r {background-color: red;} .b {background-color: blue;} .g {background-color: green;} </style> </head> <body> <div id="app" v-cloak> <!-- v-if | v-show 条件指令: v-if="变量" | v-show="变量" --> <!--1、v-if | v-show比较:两者绑定的变量值都是 true|false--> <p> <button @click="toggleAction(true)">显示</button> <button @click="toggleAction(false)">隐藏</button> </p> <!--v-if在隐藏时,不被渲染 | v-show在隐藏时,采用display: none存在--> <div class="box b1" v-if="is_show"></div> <div class="box b2" v-show="is_show"></div> <!--2、v-if、v-else-if、v-else 分支家族 --> <p> <button @click="toggleShow('red')">红</button> <button @click="toggleShow('blue')">蓝</button> <button @click="toggleShow('green')">绿</button> </p> <div class="box r" v-if="color == 'red'"></div> <div class="box b" v-else-if="color == 'blue'"></div> <div class="box g" v-else></div> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { is_show: false, color: 'red' }, methods: { toggleAction(is_show) { this.is_show = is_show; }, toggleShow(color) { this.color = color; } } }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>循环指令</title> </head> <body> <div id="app"> <div>{{ arr }}</div> <hr> <ul> <li>{{ arr[0] }}</li> <li>{{ arr[1] }}</li> <li>{{ arr[2] }}</li> </ul> <hr> <!-- v-for 循环指令: v-for="ele in 容器变量" --> <!--1、array的循环--> <ul> <li v-for="s in arr">{{ s }}</li> </ul> <hr> <!--key属性是vue的属性,表示为改标签在内存中建立缓存的依据--> <ul> <li v-for="(s, i) in arr" :key="s" b="b">第{{ i }}个:{{ s }}</li> </ul> <hr> <!--2、对象的循环--> <ul> <li v-for="v in person">{{ v }}</li> </ul> <hr> <ul> <li v-for="(v, k) in person">{{ k }}:{{ v }}</li> </ul> <hr> <ul> <li v-for="(v, k, i) in person">{{ k }}:{{ v }}:{{ i }}</li> </ul> <hr> <!--name: * | sex:*--> <!--name: * | sex:*--> <!--name: * | sex:*--> <p v-for="stu in stus"> <span v-for="(v, k, i) in stu"> <b v-if="i != 0"> | </b> <b>{{ k }}:{{ v }}</b> </span> </p> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { arr: ['aaa', 'bbb', 'ccc'], person: { 'name': 'Bob', 'age': 18, 'sex': '男' }, stus: [ { 'name': 'Alex', 'sex': '哇塞' }, { 'name': 'Egon', 'sex': '哇哦' }, { 'name': 'Jason', 'sex': '我去' } ] } }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>todolist</title> <style> li:hover { cursor: pointer; color: red; } </style> </head> <body> <div id="app"> <input type="text" v-model="msg_val"> <button @click="sendMsg">留言</button> <ul> <li v-for="(msg, i) in msgs" @click="deleteMsg(i)">{{ msg }}</li> </ul> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { // msgs: ['第一条留言', '第二条留言'], msgs: localStorage.msgs ? localStorage.msgs.split(',') : [], msg_val: '', }, methods: { sendMsg () { // 1)数据为空直接结束 if (!this.msg_val) return; // 2)数据添加到留言数组中 // this.msgs.push(this.msg_val); // 尾增 this.msgs.unshift(this.msg_val); // 首增 // 数据同步到前台数据库 localStorage.msgs = this.msgs; // 3)清空输入框 this.msg_val = ''; }, deleteMsg (index) { // console.log(index); this.msgs.splice(index, 1); // 数据同步到前台数据库 localStorage.msgs = this.msgs; } } }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>路飞导航案例</title> <style> body { margin: 0; height: 3000px; } ul { margin: 0; padding: 0; list-style: none; } </style> <style> .footer { 100%; height: 120px; background-color: rgba(0, 0, 0, 0.8); } </style> <style> .header { 100%; background-color: #ccc; position: fixed; } .header-slogan { 1200px; font: normal 14px/36px '微软雅黑'; color: #333; margin: 0 auto; } .header-nav { 1200px; margin: 0 auto; /*background-color: orange;*/ } .header-nav:after { content: ""; display: block; clear: both; } .header-logo, .header-menu { float: left; } .header-owner { float: right; } .header-logo { 118px; height: 36px; background: url("img/header-logo.svg") no-repeat; } .header-menu { margin-left: 40px; } .header-menu li { float: left; margin-top: 26px; cursor: pointer; margin-right: 20px; } .header-menu li:hover { color: #444; padding-bottom: 5px; border-bottom: 2px solid #444; } .header-owner { padding-top: 26px; } .active { color: #444; padding-bottom: 5px; border-bottom: 2px solid #444; } </style> <style> .body-box { 1200px; height: 2000px; margin: 0 auto; } .box-normal-course { background-color: pink } .box-light-course { background-color: deeppink } .box-super-course { background-color: hotpink } </style> </head> <body> <div id="app"> <div class="header"> <div class="header-slogan">老男孩IT教育集团 | 帮助有志向的年轻人通过努力学习获得体面的工作和生活!</div> <div class="header-nav"> <h1 class="header-logo"></h1> <ul class="header-menu"> <li :class="{active: page == 'normal'}" @click="togglePage('normal')">免费课</li> <li :class="{active: page == 'light'}" @click="togglePage('light')">轻课</li> <li :class="{active: page == 'super'}" @click="togglePage('super')">学位课</li> </ul> <div class="header-owner"> <div v-if="is_logout"> <span>登陆</span> | <span>注册</span> </div> <div v-else> <span>Owen</span> | <span>个人中心</span> </div> </div> </div> </div> <div class="body"> <div class="body-box box-normal-course" v-if="page == 'normal'"></div> <div class="body-box box-light-course" v-else-if="page == 'light'"></div> <div class="body-box box-super-course" v-else></div> </div> <div class="footer"></div> </div> </body> <script src="js/vue.js"></script> <script> new Vue({ el: '#app', data: { is_logout: true, page: 'normal' }, methods: { togglePage(page) { this.page = page; } } }) </script> </html>
##5、前端数据库
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>前台数据库</title> </head> <body> <h1>前台数据库</h1> </body> <script> // window.localStorage // 永久存储仓库 // window.sessionStorage // 临时存储仓库 // 存,存完注释 // localStorage['name'] = 'Owen' // 取 console.log(localStorage.name); // 存,存完注释 // sessionStorage.age = 18; // 取 console.log(['age']); // localStorage.msgs = [] // 清空 localStorage.clear(); localStorage.clear(); // localStorage.arr = [1, 2, 3]; // localStorage.obj = {'1': 1}; </script> </html>
##6、组件
#组件规则 每一个组件都是一个vue实例 每个组件均具有自身的模板template,根组件的模板就是挂载点 每个组件模板只能拥有一个根标签 子组件的数据具有作用域,以达到组件的复用
##6-1、根组件
<div id="app"> <h1>{{ msg }}</h1> </div> <script type="text/javascript"> // 通过new Vue创建的实例就是根组件(实例与组件一一对应,一个实例就是一个组件) // 每个组件组件均拥有模板,template var app = new Vue({ // 根组件的模板就是挂载点 el: "#app", data : { msg: "根组件" }, // 模板: 由""包裹的html代码块,出现在组件的内部,赋值给组件的$template变量 // 显式书写模块,就会替换挂载点,但根组件必须拥有挂载点 template: "<div>显式模板</div>" }) // app.$template </script>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <h1 id="app"> {{ msg }} </h1> <div id="main"> {{ msg }} </div> </body> <script src="js/vue.js"></script> <script> // 1、new Vue创建的是vue实例,一个实例就是一个vue组件,new出了的实例称之为根组件 // 注:在实际开发中一个页面只有一个根组件 // 2、每个组件均由 html模板 css样式 js逻辑 组成 // html模板: template,根组件的模板就采用挂载点即可,无需创建自身template // 注:挂载点是必须的(作为虚拟DOM渲染替换的依据),挂载点可以读取,作为根组件的模板,使用根组件无需书写template // 3、根组件内部可以注册使用n个子组件,子组件必须拥有自己的 html模板 css样式 js逻辑 // 如果创建子组件 | 如何使用子组件 | 父子组件间的通信 let app = new Vue({ el: '#app', data: { msg: 'app的msg', c: 'red' }, // template: '<ul>{{ msg }}</ul>', template: `<h1 id="app" :style="{color: c}" @click="action"> {{ msg }} </h1> `, methods: { action () { alert(this.msg) } } }); let main = new Vue({ el: '#main', data: { msg: 'main的msg' } }); // 知识点:利用原生js完成两个组件的交互 // 获取组件的数据 // console.log(app.msg); // 修改组件的数据 // app.msg = '12345'; main.msg = app.msg; </script> </html>
##6-2、局部组件
<div id="app"> <local-tag></local-tag> <local-tag></local-tag> </div> <script> var localTag = { data () { return { count: 0 } }, template: '<button @click="btnAction">局部{{ count }}</button>', methods: { btnAction () { this.count ++ } } } new Vue({ el: "#app", components: { 'local-tag': localTag } }) </script>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>局部组件</title> <style> .box { 200px; text-align: center; border: 1px solid black; border-radius: 10px; overflow: hidden; float: left; } .box img { 100%; } .box p { margin: 0; } .box span:hover { cursor: pointer; color: orange; } </style> </head> <body> <div id="app"> <!--<div class="box">--> <!--<img src="http://a.hiphotos.baidu.com/image/h%3D300/sign=e543b919a151f3dedcb2bf64a4eff0ec/4610b912c8fcc3cebba8b8e09c45d688d53f20fc.jpg" alt="">--> <!--<p>野兽</p>--> <!--</div>--> <!--<box></box>--> <!--<box></box>--> <!--<box-tag></box-tag>--> <!--<box-tag></box-tag>--> <!-- 问题:数据 父组件 => 子组件 父组件根据数组数据(box_data)渲染多个子组件,遍历得到的数据(box_obj)是渲染子组件的, 如何将遍历的数据传递给子组件 --> <box-tag v-for="box_obj in box_data"></box-tag> </div> </body> <script src="js/vue.js"></script> <script> // 后台的数据 let data = [ { img_url: 'img/001.jpg', img_title: '野兽1' }, { img_url: 'img/001.jpg', img_title: '野兽2' }, { img_url: 'img/001.jpg', img_title: '野兽3' } ]; // 创建局部组件 => 在根组件中注册 => 解析{}中的vue语法 => 形成组件 let box = { template: ` <div class="box"> <img src="img/001.jpg" alt=""> <p> <span @click="btnClick">点击了{{ num }}下</span> <p>野兽</p> </p> </div> `, // data: { // 错误的 // num: 0 // }, // data: function () { // 每个复用的子组件都应该有自己的一套数据,所以要用一个局部作用域存储,保证数据的隔离性 // return { // data的值还是字典,所以函数的返回值是字典即可 // num: 0 // } // }, data () { return { num: 0 } }, methods: { btnClick () { // alert(123) this.num += 1; } } }; new Vue({ el: '#app', components: { // box, // key与value变量同名 boxTag: box, // js支持的驼峰命名法与html的-连接有语法对应 // 'box-tag': box, }, data: { box_data: data } // 伪代码:页面的data数据可以由后台提供,前台获取后赋值给 vue data成员中的变量,vue就可以渲染到页面中 // $.ajax({ // success: function (data) { // this.box_data = data // } // }) }) </script> </html>
##6-3、全局组件
<div id="app"> <global-tag></global-tag> <global-tag></global-tag> </div> <script> Vue.component('global-tag', { data () { return { count: 0 } }, template: '<button @click="btnAction">全局{{ count }}</button>', methods: { btnAction () { this.count ++ } } }) new Vue({ el: "#app" }) </script>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>全局组件</title> </head> <body> <div id="app"> <!--<p-tag></p-tag>--> <!--<p-tag></p-tag>--> <g-tag></g-tag> <g-tag></g-tag> </div> </body> <script src="js/vue.js"></script> <script> let pTag = { template: ` <p> <span @click="action">{{ num }}</span> </p> `, data () { return { num: 0 } }, methods: { action() { this.num++; } } }; // 全局组件,通过 Vue.component('组件名', 组件对象主体); Vue.component('gTag', { template: ` <p> <span @click="action">{{ num }}</span> </p> `, data () { return { num: 0 } }, methods: { action() { this.num++; } } } ); new Vue({ el: '#app', components: { // pTag, } }) </script> </html>
##6-4、父子组件
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>父子组件</title> <style> body, h1, h2 { margin: 0; } </style> <style> .header { height: 120px; background-color: orange; } .body { height: 800px; background-color: pink; } .footer { height: 180px; background-color: brown; } </style> </head> <body> <div id="app"> <view-tag v-if="page == 'tag'" @click="action"></view-tag> <view-tag-2 v-else-if="page == 'tag2'"></view-tag-2> </div> </body> <script src="js/vue.js"></script> <script> // 小组件 let headerTag = { template: ` <div class="header"> <h1 style="text-align: center; line-height: 120px">头</h1> </div> `, }; let footerTag = { template: ` <div class="footer" > <h2 style="text-align: center; line-height: 180px">尾</h2> </div> `, }; // 页面组件 let viewTag = { template: ` <div class="view-tag"> <header-tag></header-tag> <div class="body" style="background-color: lawngreen"></div> <footer-tag></footer-tag> </div> `, components: { headerTag, footerTag, } }; let viewTag2 = { template: ` <div class="view-tag"> <header-tag></header-tag> <div class="body" style="background-color: cyan"></div> <footer-tag></footer-tag> </div> `, components: { headerTag, footerTag, } }; // 根组件 new Vue({ el: '#app', data: { // 问题:数据 子组件 => 父组件 // page的值需要在父组件中修改,单击事件只能在子组件中触发 // 子组件触发事件后将要修改的值传出给父组件,在父组件中完成数据的修改 page: 'tag' }, components: { viewTag, viewTag2, }, methods: { action () { alert('给组件标签绑定事件无法激活') } } }) </script> </html>
##6-5、数据父传子
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>父传子</title> </head> <body> <div id="app"> <!--总结: 1)父组件模板中写子组件标签 2)父组件的数据绑定给子组件标签的自定义属性 3)在子组件内部通过props拿到自定义属性 4)使用自定义属性就可以获得父组件的数据 --> <sub-tag :a="msg"></sub-tag> </div> </body> <script src="js/vue.js"></script> <script> let subTag = { // 子组件通过props实例成员获取自身自定义属性 props: ['a'], template: ` <div> <h1>{{ a }}</h1> </div> ` }; new Vue({ el: '#app', data: { msg: '父级数据' }, components: { subTag, } }) </script> </html>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>父传子案例</title> <style> .box { 200px; text-align: center; border: 1px solid black; border-radius: 10px; overflow: hidden; float: left; } .box img { 100%; } .box p { margin: 0; } .box span:hover { cursor: pointer; color: orange; } </style> </head> <body> <div id="app"> <box-tag v-for="box_obj in box_data" :box_obj="box_obj"></box-tag> </div> </body> <script src="js/vue.js"></script> <script> let boxTag = { props: ['box_obj'], template: ` <div class="box"> <img :src="box_obj.img_url" alt=""> <p> <span @click="btnClick">点击了{{ num }}下</span> <p>{{ box_obj.img_title }}</p> </p> </div> `, data () { //data要定义为函数形式,函数就存在了作用域,这样就可以达到隔离性 return { num: 0 } }, methods: { btnClick () { this.num += 1; } } }; // 后台的数据 let back_data = [ { img_url: 'img/001.jpg', img_title: '野兽1' }, { img_url: 'img/002.jpg', img_title: '野兽2' }, { img_url: 'img/003.jpg', img_title: '野兽3' } ]; new Vue({ el: '#app', data: { box_data: back_data }, components: { boxTag, } }) </script> </html>
##6-5、数据子传父
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div id="app"> <h1>{{ title }}</h1> <sub-tag @send_val="recv_val"></sub-tag> </div> </body> <script src="js/vue.js"></script> <script> let subTag = { template: ` <div> <input type="text" v-model="val"> <button @click="changeTitle">修改</button> </div> `, data () { return { val: '' } }, methods: { changeTitle () { if (!this.val) return; // 如果有数据,将数据发生给父组件 this.$emit('send_val', this.val); this.val = ''; } } }; new Vue({ el: '#app', data: { title: '父组件标题' }, components: { subTag }, methods: { recv_val (val) { this.title = val; } } }) </script> </html>
##7、Vue-CLI项目搭建
##7-1、环境搭建
#1、安装node 官网下载安装包,傻瓜式安装:https://nodejs.org/zh-cn/ #2、安装cnpm npm install -g cnpm --registry=https://registry.npm.taobao.org #3、安装脚手架 cnpm install -g @vue/cli #4、如果安装出现问题 可执行 npm cache clean --force
##7-2、项目创建
1、创建项目 vue create 项目名 // 要提前进入目标目录(项目应该创建在哪个目录下) // 选择自定义方式创建项目,选取Router, Vuex插件
启动 cnpm run serve / ctrl+c // 要提前进入项目根目录 访问: http://localhost:8080/
##7-2、创建好的vue项目怎么移动到新的环境
1、拷贝文件除了node_modules该文件夹,其余文件拷贝到新得环境中 2、cmd进入新的项目目录,执行cnpm install 从新安装依赖 3、通过pycharm打开新建的vue项目 4、在pycharm中编辑该项目,点击edit编辑,新建(+号)服务、选择npm
5、安装vue页面脚本
如果没有提示安装的话 取setting中pluging
6、安装完成重启pycharm
##7-3、认识项目
node_modules:项目依赖 public:公用文件 favicon.ico:页面标签图标 index.html:项目的唯一页面(单页面) src:项目开发文件目录 assets:静态资源 css|js|img components:小组件 *.vue views:视图组件 *.vue App.vue:根组件 main.js:主脚本文件 程序入口文件 router.js:路由脚本文件 - vue-router store.js:仓库脚本文件 - vuex *.xml|json|js:一系列配置文件 README.md:使用说明
import Vue from 'vue' // node_modules下的依赖直接写名字 import App from './App.vue' // ./代表相对路径的当前目录,文件后缀军可以省略 import router from '@/router.js' // @ 代表src的绝对路径 import store from './store' // 在main中配置的信息就是给整个项目配置 // 已配置 vue | 根组件App | 路由 | 仓库 // 以后还可以配置 cookie | ajax(axios) | element-ui Vue.config.productionTip = false; // Tip小提示 // 配置reset.css import '@/assets/css/reset.css' // new Vue({ // router, // store, // render: h => h(App) // }).$mount('#app') new Vue({ el: '#app', router: router, store, // render: function (fn) { // return fn(App) // } // 解释:function (h) {return 1} | (h) => {return 1} | h => 1 render: readTemplateFn => readTemplateFn(App) });
template> <!-- 模板区域 --> </template> <script> // 逻辑代码区域 // 该语法和script绑定出现 export default { } </script> <style scoped> /* 样式区域 */ /* scoped表示这里的样式只适用于组件内部, scoped与style绑定出现 */ </style>
##7-4、项目功能
##路由功能
{ path: '/', name: 'home', // 路由的重定向 redirect: '/home' } { // 一级路由, 在根组件中被渲染, 替换根组件的<router-view/>标签 path: '/one-view', name: 'one', component: () => import('./views/OneView.vue') } { // 多级路由, 在根组件中被渲染, 替换根组件的<router-view/>标签 path: '/one-view/one-detail', component: () => import('./views/OneDetail.vue'), // 子路由, 在所属路由指向的组件中被渲染, 替换该组件(OneDetail)的<router-view/>标签 children: [{ path: 'show', component: () => import('./components/OneShow.vue') }] }
<!-- router-link渲染为a标签 --> <router-link to="/">Home</router-link> | <router-link to="/about">About</router-link> | <router-link :to="{name: 'one'}">One</router-link> | <!-- 为路由渲染的组件占位 --> <router-view />
// router的逻辑转跳 this.$router.push('/one-view') // router采用history方式访问上一级 this.$router.go(-1)
##路由案例
<template> <div> <h1 :class="{active:is_active}" @click="btnClick">owen组件</h1> </div> </template> <script> export default { data (){ return { is_active : false } }, methods:{ btnClick(){ this.is_active = !this.is_active } } } </script> <style scoped> .active{ color: red; } </style>
<!-- views/About.vue --> <template> <div class="about"> <h1>This is an about page</h1> <h2>好</h2> <!-- 使用组件 --> <owen-comp></owen-comp> <OwenComp></OwenComp> </div> </template> <script> // import OwenComp from '../components/OwenComponent' import OwenComp from '@/components/OwenComponent' // 导入组件,组件名随意 export default { components: { OwenComp, // 注册组件 } } </script>