Vue study 入门前端万字笔记
什么是vue js
- vue.js 是前端的主流框架之一,和Angular.js React.js ,前端的三大框架
- Vue.js是一套构建用户界面的框架,只关注视屏层,
- 主要负责 M(数据)V(视图)C(业务逻辑) 中的V这一层,主要工作就是和界面打交道
- 让开发人员只需要关注业务逻辑,不再化很多的精力关心DOM操作,提高开发效率
- 官网:https://cn.vuejs.org/v2/guide/transitions.html
框架和库的区别
- 框架,是一套完整的解决方案,对项目的倾入性较大,项目如果需要更换框架,则需要重新j架构整个项目
- 库(插件):提供某个小的功能,对项目的倾入性较少,如果某个项目无法完成某些需求,可以很容易切换
后端MVC和前端MVVM
- 后端MVC
- 前端MVVM
Vue 实例
-
helloVUe
<body> <div id="app"> <p>{{massage}}</p> </div> <script src='../js/vue.js'></script> <script> var vm = new Vue({ el:'#app', data:{ massage:"hello 小毅" } }) </script> </body>
-
M 层:数据操作层
data:{ massage:"hello 小毅" }
-
V 层:视图展示{{massage}}
<div id="app"> <p>{{massage}}</p> </div
-
VM:数据处理:
var vm = new Vue({ el:'#app', data:{ massage:"hello 小毅", text:"我是小毅", html:'<h4>这是一个标题</h4>' } })
-
在差值表达式是,数据没事下载完之前出现{{massage}}的闪烁问题
-
v-cloak,可以解决差值闪烁的问题,在数据没有加载完之前,p 加载之前:display:none,加载完之后display:block
<p v-cloak>--{{massage}}--</p> //输出:--hello 小毅--
-
v-text,可以将msssage,绑定在一个标签中展示,默认没有闪烁问题,会覆盖掉以前的内容
<p v-text='text'>who are you</p> //输出:我是小毅
-
v-html,可以将内容解析成HTML格式
<p v-html='html'>这是一个html</p> //输出:这是一个标题
-
总结
闪烁问题 | 是否替换掉以前的内容 | 是否转义输出 | |
---|---|---|---|
差值表达式 | 有(用 v-cloak解决) | 否,只是在占位的地方显示 | 否,原文输出 |
v-text | 无 | 是,v-text会覆盖以前的内容 | 否,原文输出 |
v-html | 无 | 是,v-html会覆盖以前的内容 | 是,如果有标签 |
v-bind
-
v-bind属性告诉浏览器,这个一个变量,
<input type="button" v-bind:value="title"> <input type="button" :value="'hello'+title">//简写模式,既然是变量,就可以进行变量的增加
v-on
-
v-on 邦定事件,在data,同级的methods下声明函数
<input type="button" v-bind:value="title" v-on:click='show'> <input type="button" v-bind:value="title" v-on:mouseover='show'> <input type="button" :value="'hello'+title" v-on:click = 'show()'> methods:{ show:function(){ alert("hello 小毅") } }
-
做一个实例,把字符串最前的一个字,放到字符串尾部,不停循环,
//html <div id="app"> <input type="button" value="runing" v-on:click="run"> <input type="button" value="stop" v-on:click="stop"> <!-- <input type="button" value="stop" > --> <h4>{{message}}</h4> </div> <script> var vm = new Vue({ el: "#app", data: { message: "家强牛逼,家强牛!", intervalId:null }, methods: { run() { if(this.intervalId != null){return;} //箭头函数,这样解决普通函数this指向问题 this.intervalId = setInterval(()=>{ var start = this.message.substring(0, 1)//截取第一个字符 var end = this.message.substring(1)//截取第一个字符到最后的一个字符 this.message = end + start //把最后的字符和第一字符相加 } ,300) }, stop(){ clearInterval(this.intervalId)//停止定时函数 this.intervalId=null } } }) </script>
v-model 双向数据绑定
-
v-bing 只能实现数据的单向绑定
-
v-model 可以实现数据的双向绑定,实现的用户的交互
<div id="app"> <p>{{message}}</p> <input type="text" v-model:value="message"> </div>
-
v-model 只能运用在表单元素中
input(radio,text,address,emaill) select checkbox textarea
-
例子
<div id="app"> <input type="text" v-model='number1'> //数字1 <select v-model="option"> //选择操作符 <option value="+">+</option> <option value="-">-</option> <option value="*">*</option> <option value="/">/</option> </select> <input type="text" v-model="number2"> //数字1 <input type="button" value="=" @click="conputer"> //计算 <input type="text" v-model="result"> //显示结果 <p>number1:{{number1}}</p> <p>number2:{{number2}}</p> <p>结果:{{result}}</p> </div> // javascript <script> var vm = new Vue({ el: "#app", data: { number1: 0, number2: 0, result: 0, option: '+', }, methods: { conputer() { switch (this.option) { case '+': this.result = parseInt(this.number1) + parseInt(this.number2) break; case '-': this.result = parseInt(this.number1) - parseInt(this.number2) break; case '*': this.result = parseInt(this.number1) * parseInt(this.number2) break; case '/': this.result = parseInt(this.number1) / parseInt(this.number2) break; } } } }) </script>
-
对以上计算函数进行改进,利用 eval()方法对字符串解析执行
conputer() { var codestr = 'parseInt(this.number1) ' + this.option + 'parseInt(this.number2)' this.result = eval(codestr) }
-
在对以上例子进行改进,要求如下:
1、在鼠标进入输入框,清空默认数字 0, 2、当两个输入框改变或者操作符改变,自动输出结果
v-on的缩写和事件修饰符
-
事件修饰符
1、.stop 阻止冒泡 2、.prevent 阻止默认事件 3、.capture 添加2020年7月9日14:56:13侦听器时使用事件捕获模式 4、.selt 只当事件在该元素(比如不是子元素)触发时触发回调 5、.once 事件只触发一次
-
先定义几个函数,和简单的html代码
methods:{ div1Handler(){ console.log("触发了 inner div 的点击事件") }, btnHandler(){ console.log("触发了 btn 按钮 的点击事件") }, linkClick(){ console.log('触发了连接的点击事件') } }
-
事件的冒泡机制,点击button,会触发button 的事件,再冒泡触发父级元素的div 的事件
<div id="app"> <div class="inner" @click="div1Handler"> <input type="button" value="按钮" @click="btnHandler"> </div> </div>
-
使用.stop阻止冒泡,只触发 button 的事件,div的事件没有触发
<div class="inner" @click="div1Handler"> <input type="button" value="按钮" @click.stop="btnHandler"> </div>
-
使用.self 实现只有点击当前元素(div)的时候,才会触发事件的处理函数(通过冒泡和捕获不会再触发事件),点击button 是不会触发的事件的 div 的事件的。
<div class="inner" @click.self="div1Handler"> <input type="button" value="按钮" @click.stop="btnHandler"> </div>
-
使用.prevent阻止默认事件,只触发绑定的事件,阻止了跳转,from表单也可以使用这个方法
<a href="http://www.baidu.com" @click.prevent='linkClick'>百度一下</a>
-
使用.capture捕获机制,点击按钮时,先触发 div的事件,在触发button 的事件,由外而内
<div class="inner" @click.capture="div1Handler"> <input type="button" value="按钮" @click.stop="btnHandler"> </div>
-
使用.once,只触发一次事件
<a href="http://www.baidu.com" @click.prevent.once='linkClick'>百度一下</a>
通过属性绑定设置样式class
-
定义几个样式
<style> .color { color: brown; } .thin{ font-weight: 200; } .italic{ font-style: italic; } .active{ letter-spacing: 0.5em; } </style>
-
数组,利用v-bind数据绑定,不需要在data{}里面声明class Name
<h2 v-bind:class="['color','active','thin']">这是一个标题</h2> <h2 :class="['color','active','thin']">这是一个标题</h2>
-
数组中使用三元表达式
<h2 :class="[1<2?'color':'']">这是一个标题</h2>
-
数组中嵌套对象
<h2 :class="['color',{'active':true}]">这是一个标题</h2> <h2 :class="['color',{'active':flase}]">这是一个标题</h2>
-
直接使用对象
<h2 v-bind:class="{color:false,thin:true,italic:'true',active:true}">这是一个标题</h2> <h2 v-bind:class="calssObj">这是一个标题</h2> data: {//在data声明一个对象 calssObj:{color:false,thin:true,italic:'true',active:true} }
绑定style行内样式
-
直接在元素上通过 :style 的形式,书写样式对象
<h2 v-bind:style="{'font-style':'italic','font-weight':200}">行内样式style</h2> <h2 :style="{'font-style':'italic','font-weight':200}">行内样式style</h2>
-
将样式对象,定义到data中,并直接引用:style中
<h2 :style='H2Style'>行内样式style</h2> data: { H2Style: { color: 'pink', 'font-style': 'italic', }, H2Style2: { 'font-weight': 200 }, }
-
在:style 中,引用多个data上的样式
<h2 :style="[H2Style,H2Style2]">行内样式style</h2>
v-for
-
迭代数字
<p v-for = "(i,index,b) in 10"> {{index}}这是第{{i}}次循环</p>
-
循环普通数组
<p v-for="(item,index) in list">{{index}}号索引:{{item}}</p> data: { list: [1, 2, 3, 4, 5] }
-
循环对象数组
<p v-for="(user,index) in list">{{index}}---{{user.id}}----{{user.name}}</p> data: { list:[ {id:1,name:'小毅'}, {id:2,name:'小花'}, {id:3,name:'小狗'}, {id:4,name:'小猫'} ] }
-
循环对象
<p v-for="(value,key) in user">{{key}}:{{value}}</p> data: { user:{ id:1, name:"小毅", gender:'男', age:18 } }
-
循环嵌套对象
data: { users:{ 小毅:{ height:170, love:'running' }, 小猫:{ height:20, love:'sleep' }, 小狗:{ height:40, love:"抓老鼠" } } }
-
案列,如果没有指定 :key ,那么选定的框只是选中第 N个,意思就是说,当添加的一个对象的还是,还是选中第N个,那么如果,在对象数组前面添加的时候,就会出现问题。
<div id="app"> <div> <label>Id<input type="text" v-model="id"></label> <label>Name<input type="text" v-model="name"></label> <input type="button" value="添加" @click='add'> </div> //如果没有:key 在数组前面添加元素的是好会有bug <p v-for="item in list" :key="item.id"> {{item.id}}---{{item.name}} <input type="checkbox"> </p> </p> </div> data: { id: '', name: '', list: [ {id: 1, name: "小毅"}, {id: 2, name: "小花"}, {id: 3, name: "小猫"}, {id: 4, name: "小狗"} ] }, methods: { add() { // this.list.push({id:this.id,name:this.name}) this.list.unshift({id:this.id,name:this.name}) } }
v-if 和 v-show
-
如果为ture: v-show 和v-if 都是display:block
<div id="app"> <p v-show="true">这是v-show</p> <p v-if = "true">这是v-if</p> </div>
-
如果为false: v-show 状态是:display:none ,v-if 是直接删掉元素
<div id="app"> <p v-show="false">这是v-show</p> <p v-if = "false">这是v-if</p> </div>
-
v-show 的特点:不会每次重新进行DOM的元素删除和创建,知识切换了元素的display:none样式,有较高的初始渲染消耗
-
v-if的特点:每次直接删除和创建DOM元素,有较高的切换消耗
定义全局过滤器
-
定义一个全局过滤器
Vue.filter('dateFormat',function(dateStr,pattern){ //根据给定的字符串,得到特定的时间 var dt = new Date(dateStr) //yyyy-mm-dd var y = dt.getFullYear(); var m = dt.getMonth() + 1; var d = dt.getDate(); if(pattern.toLowerCase() === 'yyyy-mm-dd'){ return `${y}-${m}-${d}` }else{ var hh = dt.getHours() var mm = dt.getMinutes() var ss = dt.getSeconds() return `${y}-${m}-${d} ${hh}:${mm}:${ss}` } }) Vue.filter('dateFormat',function(dateStr,pattern){ //根据给定的字符串,得到特定的时间 var dt = new Date(dateStr) //yyyy-mm-dd var y = dt.getFullYear(); var m = dt.getMonth() + 1; var d = dt.getDate(); if(pattern.toLowerCase() === 'yyyy-mm-dd'){ return `${y}-${m}-${d}` }else{ var hh = dt.getHours() var mm = dt.getMinutes() var ss = dt.getSeconds() return `${y}-${m}-${d} ${hh}:${mm}:${ss}` } })
字符串填充:padStar()
-
String.prototype.padStart(maxLength, fillString=’’)
-
String.prototype.padEnd(maxLength, fillString=’’)
-
第一个参数是填充完之后的最大长度,第二个参数是用什么来填充
<div id="app"> <input type="button" value="填充" @click='test'> <p v-for="item in list">{{item}}</p> <p v-for="item in newList">{{item}}</p> </div> <script> var vm = new Vue({ el:"#app", data:{ list:[ 1,3,5,69 ], newList:[] }, methods:{ test(){ this.list.forEach(item=>{ this.newList.push(item.toString().padStart(2,'0')) }) } } }) </script>
键盘事件和自定义按键修饰符
-
系统自带的按键修饰符
.enter .tab .delete .esc .up .down .left .right
-
注册键盘事件
<input type="button" value="添加" @keyup.enter= "add"></input> <input type="button" value="添加" @keyup.113= "add"></input>
-
自定义全局按键修饰符
Vue.config.keyCodes.f2 =113 //配置f2按键修饰符 //如果没有配置,那么就不会触发事件,因为没有系统没有这个按键修饰符 <input type="button" value="添加" @keyup.f2= "add"></input>
-
键盘弹起事件,如果没有指定那个键或者键盘码,那么随便按哪个键盘,都会触发事件
<input type="button" value="添加" @keyup= "add"></input>
自定义指令
-
使用 Vue.directive() 定义全局指令, v-focus
-
参数1:指令的名称,在定义的时候不用加上前缀 v- ,直接focus,但是在调用搞定时候,一定要加 v-
-
参数2:是一个对象,这个对象身上,有一些 指令相关的函数,这些函数可以在特定的阶段,执行相关的操作
-
自定义全局指令案例,可以在两个地放定义指令,一个是在一个新的script标签里(不是和new Vue 在同一个script),另一地方是,在创建Vue实例的new Vue 同一个script 标签里面,全局定义的
<div id='app'> <input type="text" v-model="value" v-focus v-model="value"> </div> <div id='app2'> <!-- <input type="text" v-model="value" v-focus v-model="value"> --> </div> //自定义全局指令,不是和创建Vue实例同一个script <script> Vue.directive('focus',{ bind:function(el){ console.log(el) }, inserted:function(el){ el.focus() }, update:function(el){ console.log("数据更新了") } }) </script> //自定义全局指令,和创建Vue实例同一个script <script>//自定义全局指令 Vue.directive('focus',{ bind:function(el){ console.log(el) }, inserted:function(el){ el.focus() }, update:function(){//当数据更新时触发 console.log("数据更新了") } }) var vm = new Vue({ el:'#app', data: { value:"哈哈" }, }) var vm = new Vue({ el:'#app2', data: { value:"嘿嘿" } }) </script>
-
自定义字体颜色指令
<div id='app'> <input type="text" v-model="message" v-color> </div> <script> Vue.directive('color',{ bind:function(el){ el.style.color='red' }, inserted:function(el){ el.style.color='red' } }) </script>
-
钩子函数,一个指令定义对象可以提供如下几个钩子函数 (均为可选):
Vue.directive('focus',{ bind:function(el){//只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置 console.log(el) }, inserted:function(el){//被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中) el.focus() }, update:function(){//所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有 console.log("数据更新了") } })
-
钩子函数的binding参数
<div id='app'> <input type="text" v-model="message" v-color ="'blue'"> </div> <script> Vue.directive('color',{ bind:function(el,binding){ el.style.color = binding.value console.log(binding.name) // 指令的名字:color console.log(binding.value) //指令的value:blue console.log(binding.expression) //指令的表达式:'blue' } }) var vm = new Vue({ el:'#app', data: { message:"哈哈" }, }) </script>
-
自定义私有指令
//有效果 <div id='app'><p v-fontweight="900">这是app1</p></div> //没有效果 <div id='app2'><p v-fontweight="900" v-fontcolor = "'red'">这是app2</p></div> <script> var vm2 = new Vue({ el:'#app2', //绑定 app2 的div directives:{//注意:这是多了一个 "s" 'fontweight':{ //自定义字体粗细的私有指令 bind:function(el,binding){ el.style.fontWeight = binding.value } }, 'fontcolor':{ //自定字体颜色的指令 bind:function(el,binding){ el.style.color = binding.value } } } }) </script>
-
函数简写,你可能想在
bind
和update
时触发相同行为,而不关心其它的钩子<div id='app'> <p v-fontsize='32'>hello 小毅!</p> </div> <script> var vm = new Vue({ el:'#app', directives:{//注意:这是多了一个 "s" 'fontsize':function(el,binding){ //这里相当于同时把函数现在 bind 和 updat的钩子函数中 el.style.fontSize = parseInt(binding.value)+"px" } } }) </script>
生命周期函数-组件创建期间的4个钩子函数
-
四个类型的函数
//创建 beforeCreate(){}, create(){}, //挂载 beforeMount(){}, mounted(){}, //数据更新 beforeUpdate(){}, update(){}, //销毁 deforeDestroy(){}, destroyed(){}
-
学习过属性
<script> var vm = new Vue({ el:'#app', data: {}, methods: {}, filters:{}, directive:{}, components:{}, beforeCreate(){}, create(){}, beforeMount(){}, mounted(){}, beforeUpdate(){}, update(){}, deforeDestroy(){}, destroyed(){} }) </script>
vue-resource 发起get post jsonp 请求
-
案列
<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script> <script src="https://cdn.staticfile.org/vue-resource/1.5.1/vue-resource.min.js"></script> <div id="app"> 请输入关键字:<input type="text" v-model="keyword" @keyup="sendJsonP(keyword)"> <ul> <li v-for="r in result">{{r}}</li> </ul> </div> <script> window.onload = function () { new Vue({ el: '#app', data: { keyword: '', result: '' }, methods: { sendJsonP(keyword) { let url = 'https://www.baidu.com/sugrec?pre=1&p=3&ie=utf-8&json=1&prod=pc&from=pc_web'; this.$http.jsonp(url, { params: { wd: keyword }, jsonp: 'cb'//jsonp默认是callback,百度缩写成了cb,所以需要指定下 } }).then(res => { if (res.data.g) { this.result = res.data.g.map(x => x['q']); } else { this.result = []; } }); } } }); } </script>
结合Node手写JSONP服务器剖析JSONP原理
-
客户端 click.html
<body> <script> function showInfo(data){ console.log(data) } </script> <script scr="http://127.0.0.1:3000/getscript?callback=showInfo"></script> </body>
-
服务端 app.js cmd中,输入node app.js
// 导入 http 内置模块 const http = require('http') // 这个核心模块,能够帮我们解析 URL地址,从而拿到 pathname query const urlModule = require('url') // 创建一个 http 服务器 const server = http.createServer() // 监听 http 服务器的 request 请求 server.on('request', function (req, res) { // const url = req.url const { pathname: url, query } = urlModule.parse(req.url, true) if (url === '/getscript') { // 拼接一个合法的JS脚本,这里拼接的是一个方法的调用 // var scriptStr = 'show()' var data = { name: 'xjj', age: 18, gender: '女孩子' } var scriptStr = `${query.callback}(${JSON.stringify(data)})` // res.end 发送给 客户端, 客户端去把 这个 字符串,当作JS代码去解析执行 res.end(scriptStr) } else { res.end('404') } }) // 指定端口号并启动服务器监听 server.listen(3000, function () { console.log('server listen at http://127.0.0.1:3000') })
Vue 过度动画
-
实现动画的过渡类名class
.v-enter,是开始动画之前,还没有开始 . v-leave-to 是动画结束之后的状态,已经结束 .v-enter-active,是动画入场的过程 .v-leave-active 是动画离场的过程
-
案例:通过过渡类名实现动画,transition 标签的内容,会响应过渡类名class,transition元素,是vue官方提供的。
<style> .v-enter, .v-leave-to { opacity: 0; transform:translateX(300px)//设置动画入场开始之前和离场结束之后的位置 } .v-enter-active, .v-leave-active { transition: all 0.4s ease;//设置入场和离场的过程中的动画效果 } </style> <div id='app'> <input type="button" value="toggle" @click="flag= !flag"> <transition> <h3 v-if="flag">这是一个H3</h4> </transition> </div> <script> var vm = new Vue({ el: '#app', data: { flag:false } }) </script>
-
可以定义不同的动画
<style> //第二个动画,前缀是 v- .v-enter, .v-leave-to { opacity: 0; transform:translateX(300px)/* 设置动画入场开始之前和离场结束之后的位置*/ } .v-enter-active, .v-leave-active { /*设置入场和离场的过程中的动画效果*/ transition: all 0.4s ease; } //第二个动画,前缀我my- .my-enter, .my-leave-to{ opacity: 0; transform:translateY(300px) } .my-enter-active, .my-leave-active{ transition: all 0.8s ease; } </style>
-
transition 标签 name属性,调用不同的动画
<div id='app'> 这是调用 v- 前缀的动画 <input type="button" value="toggle" @click="flag= !flag"> <transition><h3 v-if="flag">这是一个h3</h3></transition> <hr> //这是调用 my- 前缀的动画 <input type="button" value="toggle2" @click="flag2= !flag2"> <transition name='my'><h3 v-if="flag2">这是一个h6</h3></transition> </div> <script> var vm = new Vue({ el:'#app', data: { flag:false, flag2:false } }) </script>
使用第三方库animate.css实现动画
-
animate.css:https://animate.style/
-
实现动画
<link rel="stylesheet" href="../js/animate.css"> <div id='app'> <input type="button" value="toggle" @click="flag=!flag"> <transition enter-active-class="bounceIn" leave-active-class="bounceOut"> <h3 v-if="flag" class="animated">v-if h3</h3> </transition> </div>
钩子函数
-
JavaScript 钩子
<transition v-on:before-enter="beforeEnter" //动画开始之前 v-on:enter="enter" //动画开始的过程 v-on:after-enter="afterEnter" //动画开始结束后 v-on:enter-cancelled="enterCancelled" v-on:before-leave="beforeLeave" //动画开始之前 v-on:leave="leave" //动画离场的过程 v-on:after-leave="afterLeave" // 动画离场之后 v-on:leave-cancelled="leaveCancelled" > </transition>
-
可以在methods中定义JavaScript函数
methods: { // -------- // 进入中 // -------- beforeEnter: function (el) { // ... }, // 当与 CSS 结合使用时 // 回调函数 done 是可选的 enter: function (el, done) { // ... done() }, afterEnter: function (el) { // ... }, enterCancelled: function (el) { // ... }, // -------- // 离开时 // -------- beforeLeave: function (el) { // ... }, // 当与 CSS 结合使用时 // 回调函数 done 是可选的 leave: function (el, done) { // ... done() }, afterLeave: function (el) { // ... }, // leaveCancelled 只用于 v-show 中 leaveCancelled: function (el) { // ... } }
-
当只用 JavaScript 过渡的时候,在 enter 和 leave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。
JavaScript钩子函数,实现半场动画案例
-
html部分
<style> .ball{ width:15px; height: 15px; background-color: chocolate; border-radius:50% } </style> <body> <div id='app'> <input type="button" value="加入购物车" @click="flag=!flag"> <transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter"> <div class="ball" v-show="flag"></div> </transition> </div> </body>
-
javaScript 部分,构子函数
<script> var vm = new Vue({ el:'#app', data: { flag:false }, methods: { beforeEnter(el){ console.log("before") //beforeEnter 表示动画入场之前,此时,动画未开始,可以在beforeEnter中 //设置元素开始动画之前的前始位置 el.style.transform = "translate(0,0)" }, enter(el,done){ //enter 表示动画,开始之后的样式,可以设置小球完成动画之后的,结束状态 el.offsetWidth//没有什么意义,el.offsetWidth,会强制刷新 el.style.transform = "translate(250px,250px)" el.style.transition = "all 1s ease" done() //done是afterEnter函数的引用,要应用,不然有延迟 console.log("enter") }, afterEnter(el){ //动画完成之后,会调用 this.flag = !this.flag } } }) </script>
transition-group元素实现列表动画
-
使用transition-group 包裹住要循环的li
<transition-group> <li v-for='item in list' :key="item.id"> {{item.id}} ---- {{item.name}} </li> </transition>>
-
案例,实现列表的页面的刷新入场,删除和添加的动画效果
appear 属性,实现页面展现出来的时候,入场的效果
tag 属性,指定循环的元素,默认是 span
<style> /* 动画开始前和结束后元素的位置 */ .v-enter, .v-leave-to{ opacity:0; transform: translateY(100px); } /* 动画开始入场和离场的过程的动画效果*/ .v-enter-active, .v-leave-active{ transition:all 0.8s ease; } /* 使用后续的元素,在删除的时候,有动画的效果*/ .v-move{ transition: all 0.6s ease; } .v-leave-active{ position: absolute; } </style> <div id='app'> <input type="text" v-model="id"> <input type="text" v-model="name"> <input type="button" @click="add" value="添加"> <transition-group appear tag='ul'> <li v-for='(item,i) in list' :key="item.id" @click="del"> {{item.id}} ---- {{item.name}} </li> </transition>> </div> data: { id:'', name:'', list: [ {id: 1,name: '小毅'}, {id: 2,name: '小黄'}, {id: 3, name: '小俞'}, {id: 4, name: '小陈' },]}, methods: { add(){ this.list.push({id:this.id,name:this.name}) }, del(id){ this.list.splice(id,1) } }
组件化
-
组件的创建,这些都是公有的组件,在不同的Vue实例都可以使用
<div id='app'> <mycoml></mycoml> <mycoml2></mycoml2> <mycoml3></mycoml3> <mycoml4></mycoml4> </div> //引用的外部代码,不可子div#app 里面写,不然写的代码直接响应在html页面上 <template id="teml"> <div> <h2>这是使用template 元素,在外部定义的组件结构</h2> <h4>这个方法有代码提示和高亮</h4> </div> </template> <script> const coml = Vue.extend({ //第一种 template: "<h3>这是使用Vue.extend 创建的组件</h3>" }) Vue.component('mycoml', coml) Vue.component('mycoml2',Vue.extend({//第二种 template: "<h3>这是使用Vue.extend 不用中间变量接受创建的组件</h3>" })) Vue.component("mycoml3",{//第三种,可以直接放一个对象,或者对像的名字 template: "<h3>这是使用Vue.component直接创建的组件</h3>" }) //引用的外部代码,不可子div#app 里面写,不然写的代码直接响应在html页面上 Vue.component('mycoml4',{//第四种 template:'#teml' }) </script>
-
组件的模板只能有一个根元素,不能有两个平级的元素
<template id="teml"> <div> //div 包裹着两个标题 <h2>这是使用template 元素,在外部定义的组件结构</h2> <h4>这个方法有代码提示和高亮</h4> </div> </template>
##使用components定义私有组件
-
使用components定义私有组件,只能在定义自身的Vue实例中调用
<template id="teml"> <div> <h3>这是一个私有组件</h3> <h5>通过引用外部的template</h5> </div> </template> //定义一个私有组件 var vm = new Vue({ el:'#app', components:{ login:{ template:"#teml" } }, </script>
组件中的data 和 methods
-
在组件,data是一个function,return 回来的是一个对象
<div id='app'> <mycoml></mycoml></div> Vue.component('mycoml',{ template:'<h1>这是组件中的data---id:{{id}}--name:{{name}}</h1>', data:function(){ //一个function return 一个对象 return{ id:1, name:"小毅" } } })
-
利用组件的data 和methods 做一个计数器,组件中methods中定义一个increment函数
<div id='app'> <counter></counter> <hr> <counter></counter> <hr> <counter></counter> </div> <template id="templ"> <div> <input type="button" value="加 1 " @click="increment"><br> {{count}} </div> </template> <script> var dataObj = {count:0}//在外面顶定义一个对象 Vue.component('counter',{ template:'#templ', data:function(){ //return dataObj ,如果返回的是在外面定义的对象,因为它的引用是同一个地址,所有的count会同时加 1 return{count:0}//返回这里的count,每一个组件的实例,调用的都是自己的count,他们是不同的地址,所以,不会同时加 1 }, methods:{increment(){this.count++}} }) var vm = new Vue({el:'#app', }) </script>
组件切换
-
利用v-if 和v-else ,显示登陆或注册的组件
<div id='app'> <a href="#" @click.prevent="flag=true">登录</a> <a href="#" @click.prevent="flag=false">注册</a> <login v-if="flag"></login> <register v-else="flag"></register> </div> <script> //创建两个组件 Vue.component('login', { template: "<h3>登录组件</h3>" }) Vue.component('register', { template: "<h3>注册组件</h3>" }) var vm = new Vue({ el: '#app',data:{flag:false} }) </script>
-
利用Vue提供的标签 component占位, :is =“组件名” ,实现组件的切换
<style> .v-enter, .v-leave-to{ opacity: 0; transform: translateY(250px); } .v-enter-active, .v-leave-active{ transition: all 0.5s ease; } </style> <div id='app'> <a href="#" @click.prevent="comName='login'">登录</a> <a href="#" @click.prevent="comName='register'">注册</a> <transition mode="out-in"> // mode 模式,先out再in <component :is='comName'></component> </transition> </div> <script> Vue.component('login', { template: "<h3>登录组件</h3>" }) Vue.component('register', { template: "<h3>注册组件</h3>" }) var vm = new Vue({ el: '#app',data:{comName:'login'} }) </script>
子组件的使用父组件的data和本身的data
-
在组件中,默认无法访问到父组件中data 上的数据和methods 中的方法
-
可以使用,利用属性绑定机制:v-bind: 自定义一个属性,绑定父组件中data的,再在子组件的props:[]的数组中那个定义,这样就可以在子组件中使用父组件data中的数据了
-
子组件的所有props 中的数据都是通过父组件传递给子组件的
-
子组件的data,是一个function ,返回的是一个对象。
-
子组件的data,是子组件私有的,比如:子组件通过Ajax,请求回来的数据,都可以放到data身上
-
子组件的props中的数据,都是只可读的,不能写
-
父组件中的data 都是可读可写的
<div id='app'> //v-bind: 一个自定义的属性,再把父组件的的 msg 赋值给这个自定义组件 <coml v-bind:parent="msg"></coml> </div> var vm = new Vue({ el:'#app', data: { msg:"hello,我是爸爸" }, components:{ coml:{ template:"<h1>这是子组件 -- {{ parent }}</h1>", props:['parent'] //要把自定义的组件放在props:[] 才可以在子组件中使用 }, } })
子组件通过事件调用向父组件传值
-
父组件向子组件传递方法,使用的是事件的绑定机制,v-on,自定义一个事件属性之后,把父组件的方法挂在这个事件属性上,子组件就能过通过某些方式来调用
-
下面是子组件通过用自身的事件myclick,利用emit()方法 触发自定义的事件属性,并传入子组件的sonMsg作为参数,这样,就通过自定义的事件属性调用了父组件的方法,并且把子组件的sonMsg传给了父组件的function。
<div id='app'> <com @func="show"></com> {{dataFormSon}} </div> <template id="template"> <div> <h2>这是子组件</h2> <input type="button" value="触发父组件传递的function" @click='myclick'> </div> </template> <script> var com = { template: '#template', data() { return{ sonMsg:{name:'小毅',age:20} } }, methods: { myclick(){ this.$emit('func',this.sonMsg) } } } var vm = new Vue({ el: '#app', data: { dataFormSon:null }, methods: { show(data){ this.dataFormSon = data; } }, components: { com } }) </script>
组件的案例
-
可以发表评论,可以展示评论列表
## ref获取DOM元素和组件引用
1. javaScript 获取元素
```javascript
<div id='app'>
<input type="button" value="获取元素" @click="getElement">
<h3 id="h3">hello,小毅</h3>
</div>
// 通过id 获取h3 的元素
document.getElementById('h3')
-
在创建的Vue实例vm 中,有一个ref属性,默认是空的,如果个标签 ref 属性,就可以通过ref获取元素
vm.$refs 返回一个对象,面里有使用了ref 属性的元素和组件
我们可以通过 ’ . ’ 的方式,获取 refs对象中元素和组件的data 和方法
<div id='app'> <input type="button" value="获取元素" @click="getElement"> <h3 id="h3" ref="h3">hello,小毅</h3> <h4 id="h4" ref="h4">hello</h4> <login ref="login"><login> </div> <script> var login = { data(){ return{ msg:"子组件的 msg " } }, methods:{ show(){ alert("调用了子组件的方法show()") } }, template:"<h1>这是一个组件</h1>" } var vm = new Vue({ el:'#app', methods: { getElement(){ //通过ref 获取元素 console.log(this.$refs)//3个对象{h3,h4,login} console.log(this.$refs.h3.innerText)// 通过ref获取h3中的内容 //通过 ref 获取子组件的data 和 方法 console.log(this.$refs.login.msg) this.$refs.login.show() } } , components:{ login } }) </script>
vue-router安装和基本使用
-
vue-router 依赖vue,所以要先导入vue.js 再导入vue-router.js
-
创建一个vue-router 对象,对象里有一个属性是 routes(注意没有‘R’),是一个数组,用来定义router的规则,这个routes 数组中可以放多个对象,每个对象就一个路由规则
-
每一个路由规测有两个必须的参数,path:路由链接地址,component:对应的组件
-
vue-router 提供一个标签‘router-view’,当作占位符,由路由规测匹配到的组件,就会再这里展示
<div id='app'> <!-- 展示匹配路由URL成功的组件 --> <router-view></router-view> </div> <script src='../js/vue.js'></script> <script src='../js/vue-router-3.0.1.js'></script> <script> //创建两个组件对象 var login = { template:"<h3>登录组件</h3>" } var register = { template:"<h3>注册组件</h3>" } var routerObj = new VueRouter({ routes:[//路由规测数组 {path:'/login',component:login}, //一个路由规测对象 {path:'/register',component:register}, ] }) var vm = new Vue({ el:'#app', router:routerObj //把路由对像挂到Vue的router,属性中 }) </script>
router-link 和重定向
-
router-link
-
重定向
-
tag标签
<style> /* .router-link-active, */ .active{ color:bisque; } </style> <body> <div id='app'> <router-link to="/login" tag="span">登录</router-link> <router-link to="/register">注册</router-link> <router-view></router-view> </div> <script src='../js/vue.js'></script> <script src='../js/vue-router-3.0.1.js'></script> <script> var login = {template: '<h3>登录组件</h3>' } var register = {template: '<h3>注册组件</h3>'} var routerObj = new VueRouter({ routes: [ {path: '/', redirect: '/login'}, { path: '/login',component: login }, { path: '/register', component: register} ], //linkActiveClass 默认为:router-link-active linkActiveClass:'active' }) var vm = new Vue({ el: '#app',router:routerObj}) </script>
router 动画
-
动画
<style> /* .router-link-active, */ .active{ color:bisque; } .v-enter, .v-leave-to{ opicity:0; transform: translateX(250px); } .v-enter-active, .v-leave-active{ transition:all 0.8s ease; } </style> <body> <div id='app'> <router-link to="/login" tag="span">登录</router-link> <router-link to="/register">注册</router-link> <transition mode="out-in"> <router-view></router-view> </transition> </div>
路由的两种获取参数的方法
-
query
-
params
<div id='app'> <router-link to="/login?id=10&name='小毅'">登录</router-link> <router-link to="/register/11/'小花'">注册</router-link> <router-view></router-view> </div> <script> //方法一 var login = { template:'<h2>登录 使用query获取参数:--id:{{$route.query.id}}--用户:{{$route.query.name}} </h2>', } //方法二 var register = { template:'<h2>注册 使用params 获取参数:--id:{{this.$route.params.id}}--用户:{{this.$route.params.name}}</h2>', } var routerObj = new VueRouter({ routes:[ {path:'/',redirect:'login'}, {path:'/login',component:login}, {path:'/register/:id/:name',component:register} ] }) var vm = new Vue({el:'#app', router:routerObj}) </script>
使用children 属性实现路由的嵌套
-
在路由对象中,使用children属性实现路由的嵌套
<style> .tem{ height: 500px; width:800px; background-color: bisque; } h3{ height:400px; background-color: blue;} </style> <div id='app'> <router-view></router-view> </div> <template id="template"> <div class= 'tem'> <h2>这个root 组件</h2> <router-link to='/root/children1'>登录(children1)</router-link> <router-link to='/root/children2'>注册(children2)</router-link> <router-view></router-view> </div> </template> <script> var root = {template:"#template"} var children1 = {template:'<h3>登录</h3>'} var children2 = {template:'<h3>注册</h3>'} var routerObj = new VueRouter({ routes:[ {path:'/',redirect:'root'}, {path:'/root', component:root, children:[ {path:'children1',component:children1}, {path:'children2',component:children2} ] },] }) var vm = new Vue({el:'#app',router:routerObj }) </script>
路由命名视图实现经典布局
-
给 router-view 添加一个那么 属性
<style> html,body,h1{margin:0;padding:0;} .header{background-color: magenta;} .container{display: flex;height:600px;} .left{ background-color: lightcoral; flex:2;} .main{ background-color:lightseagreen;flex:8;} </style> <div id='app'> <router-view></router-view> <div class="container"> <router-view name = 'left'></router-view> <router-view name = 'main'></router-view> </div> </div> <script> var header = {template:'<h1 class="header">header</h1>'} var leftBox = {template:'<h1 class="left">Left</h1>'} var mainBox = {template:'<h1 class="main">main</h1>'} var routerObj = new VueRouter({ routes:[ {path:'/',components:{ 'default':header, 'left':leftBox, 'main':mainBox }} ] }) var vm = new Vue({el:'#app',router:routerObj}) </script>
webpack的基本使用方法
-
新建项目的文件夹
webpack //项目名 dist //文件夹 src //文件夹 images // src 下的文件夹 css // src 下的文件夹 js // src 下的文件夹 index.html // src 下的html文件 main.js // src 下的js 文件
-
初始化项目
npm init -y
-
安装
//全局安装 npm i webpack -g //安装到项目依赖中 npm i webpack --save-dev
-
在main .js 文件中,导入其他文件(js.css),比如jquery.js 文件
// 这是main.js 文件 import $ from 'Jquery' //利用jquery 使列表隔行变色 $(function(){ $("li:odd").css('backgroundColor','lightblue') $("li:even").css('backgroundColor','green') // $('li').css('backgroundColor','red') })
-
运行webpack,运行下面的代码,在dist下有一个bundle.js 文件
webpack .\src\main.js -o .\dist\bundle.js
-
在index.html中,写一个ul>li*10,在导入dist下的bundle.js 文件,在浏览器打开index.html 即可
// 这是index.html <script src="../dist/bundle.js"></script> <ul> <li>这是第1个li</li> <li>这是第2个li</li> <li>这是第3个li</li> <li>这是第4个li</li> <li>这是第5个li</li> <li>这是第6个li</li> <li>这是第7个li</li> <li>这是第8个li</li> <li>这是第9个li</li> <li>这是第10个li</li> </ul>
webpack 配置文件
-
如果每一次修改js ,css 文件都需要用命令形式(webpack .\src\main.js -o .\dist\bundle.js)指定入口和出口文件太麻烦
-
我们可以在项目的跟目录,创建一个配置文件:webpack.config.js,在控制台运行:webpack 即可得到bundle.js,文件
const path = require('path') module.exports = { //入口,表示要使用webpack 打包那个文件 entry:path.join(__dirname,'./src/main.js'), //输出文件的配置,输出文件的目录,和文件名 output:{ path:path.join(__dirname,'./dist'), filename:'bundle.js' } }
-
webpack 工作过程
// 当在控制台运行: webpack 1、webpack发现没有通过命令行的形式指定入口和出口 2、找到配置文件,webpack.config.js 3、解析执行配置文件,导出配置对象 4、当webpack拿到配置对象后,根据入口和出口进行打包构建
webpack-dev-server的基本使用
-
每一次修改代码,要重新看效果,都需要运行webpack,很麻烦,所以我们使用webpack-dev-server
-
webpack-dev-server这个工具,可以实现自动打包编译的动能(和nodemon类似),不仅可以打包编辑项目,还可以使项目通过localhost本地的方式进行访问我们的项目,这一点和apache类似
-
安装,这个工具只能安装在项目中,不能进行全局的安装
cnpm i webpack-dev-server -D
-
webpack-dev-server 这个工具,如果想要正常运行,一定要在本地的项目中安装webpack,即使我们已经在全局中安装过了webpack
cnpm i webpack -D
-
在package.json 文件中配置webpack-dev-server ,注意在json 文件中不能写注释,字符串要用双引号
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "webpack-dev-server" },
-
安装脚手架
cnpm i webpack-cli -D
-
运行
npm run dev
-
默认访问loclhsot:8080即可访问我们的项目
-
生成的bundle.js在 根目录下,在内存中,所以在html 文件中引入这个js文件的路径一定要修改
<script src="/bundle.js"></script>
webpack-dev-server 的常用命令
-
第一种方法,也是推荐的一种,在package,中配置webpacke-dev-server
// --open => 运行完命令后打开浏览器 // --oprt 3000 => 设置端口 // --contentBase => 访问的文件路径 默认是 根目录 / // --hot => 不重新生成bundle.js 文件,只是在这个基础上加载修改的部分,而且可以同步到浏览器,不用 手动刷新 "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "webpack-dev-server --open --port 3000 --contentBase src --hot" }
-
第二种方法:在webpack.config.js 文件中配置我webpack-dev-server
// 第一步 在package.json 文件下的script 中添加 dev2 "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "webpack-dev-server --open --port 3001 --contentBase src --hot", "dev2": "webpack-dev-server" }, //第二步 在webpack.config.js 文件下配置webpack-dev-server const path = require('path') //启动热更新的 第二步 const webpack = require('webpack') module.exports = { //入口,表示要使用webpack 打包那个文件 entry:path.join(__dirname,'./src/main.js'), //输出文件的配置,输出文件的目录,和文件名 output:{ path:path.join(__dirname,'./dist'), filename:'bundle.js' }, devServer:{ open:true, port:3000, contentBase:'src', hot:true //启动热更新的 第一步 }, plugins:[ new webpack.HotModuleReplacementPlugin() 启动热更新的 第三步 ] }
html-webpack-plugin
-
在内存中生成html
-
安装
cnpm i html-webpack-plugin -D
-
配置,在webpack.config.js 文件中配置
//导入插件 const htmlWebpaPlugin = require('html-webpack-plugin') // 在plugins 中添加插件配置 plugins:[ new webpack.HotModuleReplacementPlugin(), 启动热更新的 第三步 new htmlWebpaPlugin({ template:path.join(__dirname,'./src/index.html'), //把哪个文件生成到内存中 filename:'index.html' // 生成到内存中的文件的文件名 }) ]
-
当使用了html-webpack-plugin 之后,就不需要手动处理bundle.js 的引用路径了,因为这个插件,会自动帮我们创建一个合适的 script 并且引用了正确的路径
css-loader处理css文件
-
webpack默认只能处理JS类型的文件,如果需要处理非JS类型的文件,我们需要手动安装一些合适的第三方加载器
-
安装style-loader 和 css-loader
cnpm i style-loader css-loader -D
-
在webpack.config.js 配置文件,新增一个配置节点module,他是一个对象,在这个module对象中,有个rules 属性,这个rules 属性是一个数组,这个数组中,存放了所有第三方文件的匹配和处理规则
//这是webpack.config.js 配置文件 module:{// 这个节点,用于配置 所有的第三方模块 加载器 rules:[//所有第三方模块的 匹配规则 {test:/\.css$/,use:['style-loader','css-loader'], ] } // css目录下,新建一个index.css 文件,并写入样式 li{ list-style: none; } // 在main.js 中导入css样式文件 import './css/index.css'
-
第三方loader的调用过程
1、wenbpack发现,我们并没有通过命令的形式,给他指定入口和出口 2、webpack就去根目录中,查找一个叫做"webpack.config.js"的配置wenjian 3、webpack 解析配置文件,当解析完配置文件之后,就得到了配置文件中导出的配置对象 4、webpack 拿到配置对象后,就拿到了配置对象中,指定的入口和出口,然后 进行打包和构建
配置处理less文件的loader
-
安装
cnpm i less-loader -D cnpm i less -D // less 是less-loader 的内部依赖文件
-
配置使用
//配置 module:{// 这个节点,用于配置 所有的第三方模块 加载器 rules:[//所有第三方模块的 匹配规则 {test:/\.css$/,use:['style-loader','css-loader']}, {test:/\.less$/,use:['style-loader','css-loader','less-loader']} ] // 在css 目录先创建一个index.less文件并写入内容 ul{ margin:0; padding: 0; } // 在main.js 中导入.less 文件 import './css/index.less'
配置处理scss文件的loader
-
安装
cnpm i sass-loader -D cnpm i node-sass -D //node-sass 是sass-loader 的内部依赖
-
配置使用
//配置 module:{// 这个节点,用于配置 所有的第三方模块 加载器 rules:[//所有第三方模块的 匹配规则 {test:/\.css$/,use:['style-loader','css-loader']}, {test:/\.less$/,use:['style-loader','css-loader','less-loader']}, {test:/\.scss$/,use:['style-loader','css-loader','sass-loader']} ] // 在css 目录先创建一个index.scss文件并写入内容 html,body{ margin:0; padding:0; } li{ font-size: 12px; line-height: 30px; } // 在main.js 中导入.less 文件 import './css/index.scss'
webpack 项目初始化
-
简单的描述一下webpack 的配置
npm init -y webpack ./src/main.js ./dist/bundle.js //全局安装了wepback,但是这个办法太麻烦 cnpm i webpack-dev-server -D //安装一个工具,可以实时打包 cnpm i webpack -D //本地安装一个webpacn 新建一个webpack.config.js 配置文件配置入口,和出口 在pakage.json的script节点下配置dev 第一种方法:"dev":"webpack-dev-server --open --port 3000 --contentBase src --hot" cnpm i html-webpack-plugin -D //可以在内存中生成html 的工具 配置 html-webpack-plugin plugins:[ template:path.jion(__dirname,'./src/index.html'), filename:'index.html' ] // 处理样式的 loader cnpm i style-loader css-loader -D //处理.css文件 cnpm i less-loader less -D //处理.less文件 cnpm i sass-loader node-sass -D //处理.less文件 配置所有第三方某块 module:{ rules:[ {test:/\.css$/,use:['style-loader','css-loader'}, {test:/\.less$/,use:['style-loader','css-loader','less-loader'}, {test:/\.scss$/,use:['style-loader','css-loader','sass-loader'} ] } //在main.js 中引入样式文件 import './css/index.css' import './css/index.less' import './css/index.scss'
webpack中url-loader 的使用 处理图片和字体图标
-
webpack 默认是无法处理css文件中的 url地址,不管是图片和还是字体库,只要是URL 都处理不了
-
安装配置url-loader
//安装 cnpm i url-loader file-loader -D //配置 module:{// 这个节点,用于配置 所有的第三方模块 加载器 rules:[//所有第三方模块的 匹配规则 {test:/\.css$/,use:['style-loader','css-loader']}, {test:/\.(jpg|png|gif|bmp|jpeg)$/,use:'url-loader?limit=30&name=[name].[ext]'},//处理图片 URL {test:/\.(ttf|eot|svg|woff|woff2)$/,use:'url-loader'}// 处理图标 ] }
webpack中bable 的配置
-
webpack中,默认只能处理一部分的ES6的新语法,一些更高级的ES6语法或ES7语法webpack就无能为力。
-
可以通过第三方loader 把更高级的语法转为低级的语之后,把结果交给webpack去打包到bundle.js中
-
通过第三方loader,Babel ,可以帮我们把高级的语法转换为低级的语法。
-
可能会版本不对应
babel-loader 8.x对应babel-core 7.x babel-loader 7.x对应babel-core 6.x
-
安装
cnpm i babel-core babel-loader babel-plugin-transform-runtime -D cnpm i babel-preset-env babel-preset-stage-0 -D cnpm i --save-dev babel-loader@7.1.5 //如果版本不对应,可以降低babel-loader的版本
-
配置
//在webpack.config.js module:{ rules:[ {test:/\.js$/,use:'babel-loader',exclude:/node_modules/} ] } //在跟目录新建一个.babelrc 的文件,并写入 { "presets":["env","stage-0"], "plugins":["transform-runtime"] }
-
babel-preset-env,是比较新的ES6语法,他包含了所有和ES*相关的语法
使用vue实例render 方法渲染组件
-
使用conponents
<div id='app'> <login></login> </div> <script> var login = { template:'<h1>这是登录组件</h1>' } var vm = new Vue({ el:'#app', components:{ login } }) </script>
-
使用render
<div id='app'> </div> <script> var login = { template:'<h1>这是登录组件</h1>' } var vm = new Vue({ el:'#app', render:function(createElements){//createElements 是一个方法,调用它,可以把指定的组件模板渲染为html结构 return createElements(login) } }) </script>
-
这两者的区别
// 1、render会替换页面中el 指定的那个容器,容器的全部东西都会消失,只有组件的内容 // 2、components就像差值表达式一样,只是插入这个组件
如何在webpack构建的项目中使用vue开发
-
在网页中
1、使用script标签,引用vue的包 2、在index页面中,创建一个 id 为 app 的div 容器 3、通过 new Vue 得到一个vm 的实例
-
在webpack的项目中
-
按装Vue
cnpm i vue -S
-
在webpack中,在main.js 使用import Vue from ‘vue’ 导入的Vue 构造函数,功能不完整,只能提供
import Vue from 'vue'
-
包的查找过程
1、在项目根目录中有没有node_modules的文件夹 2、在node_modules中,找对应的vue文件夹 3、在vue 文件夹的package.json 的配置文件中,有一个main 属性 4、main属性指定了这个包在被加载时候的入口文件,默认: "main": "dist/vue.runtime.common.js",
-
在main.js 中导入VUE,创建一个实例
//导入vue 的第一种方法 import Vue from 'vue'//这是阉割版的vue.js(vue.runtime.common.js) //导入vue 的第二种方法 import Vue from '../node_modules/vue/dist/vue.js'// 这是完全版的vue.js //导入vue 的第三种方法 是对第二种方法的一个改进 import Vue from 'vue' // 先在main.js 导入vue //再在webpack.config.js 中和entry,output,module,plugins,平级再建一个配置节点,resolve resolve:{ alias:{// 修改Vue被导入时候包的路径 "vue$":"/node_modules/vue/dist/vue.js" } } ------------------------------------------------------------------------------------- //在main.js中创建Vue实例 var vm = new Vue({ el:'#app', data:{ a:"在webpack 中使用vue" } }) ------------------------------------------------------------------------------------- // 在index.html 中创建一个 id=app 的div容器 <div id="app"> <p> hello{{a}}</p> </div>
在webpach 中使用vue 结合render渲染组件到指定的容器中
-
默认webpack 无法打包 .vue 文件,需要相关的loader
-
安装配置
//安装 cnpm i vue-loader vue-template-compiler -D //配置,在webpack.config.js的 {test:/\.vue$/,use:"vue-loader"} const VueLoaderPlugin = require('vue-loader/lib/plugin'); plugins:[ new VueLoaderPlugin()// 把VueLoaderPlugin放到plugins中 ],
-
定义一个login.vue 文件
<template> <div> <h1 @click="show">这是登录组件,是使用.vue 文件定义的 {{msg}}</h1> </div> </template> <script> export default{ data(){ return { msg:"家强牛逼" } }, methods:{ show(){ console.log('调用了 login.vue 中的show 方法'), } } } </script> <style> </style>
-
在main.js中,导入vue并创建一个实例,用render 的方法,渲染 login.vue组件
//导入vue ,这是在only runtime 的模式下的vue import Vue from 'vue' import login from './login.vue' var vm = new Vue({ el:'#app', // render:function(createElements){ // return createElements(login) // } render:c=>c(login)// 这是render渲染用箭头函数的简写 })
-
在html中创建一个容器,render 方法渲染的组件,会把这个容器里面的内容全部替换
<div id="app"> <p> hello{{a}}</p> </div>
export default 和export 导入和导出
-
在node.js中,向外暴露成员的形式和导入。
module.exports = {} exports {} var test =require('test')
-
在ES6 中,用export default 和export 向外暴露成员
//这个test.js 文件
export default { // export default 一个文件只能暴露一个对象
name:"小毅",
age:20
}
export var title ="家强牛逼"
export var content ="小毅牛逼"
-
接收,export default 和 export 暴露的对象
//这是main.js 文件 import test,{title,content} from './test' console.log(test) console.log(title+"----"+content)
webpack 使用vue-router
-
中文官方文档:https://router.vuejs.org/zh/
-
下载,安装,使用
cnmp i vue-router -S//下载 import Vue from 'vue' import VueRouter from 'vue-router'// 导入vue-router 包 Vue.use(VueRouter) // 手动安装 VueRouter
-
新建3 个.vue 文件的组件
//App.vue ------------------------------------------ <template> <div> <h1>这是 App 组件</h1> <router-link to="/account">Account</router-link> <router-link to="/goodslist">Goodslist</router-link> <router-view></router-view> </div> </template> <script> </script> <style> </style> //account.vue ---------------------------------------- <template> <div> <h1>这是 Account 组件</h1> </div> </template> <script> </script> <style> </style> //goodslist.vue ------------------------------------------ <template> <div> <h1>这是 GoodsList 组件</h1> </div> </template> <script> </script> <style> </style>
-
导入.vue文件的组件
// 导入组件 import app from './App.vue' import account from './main/account.vue' import goodslist from './main/goodslist.vue'
-
使用vue-router
//创建路由对象 var router = new VueRouter({ routes:[ {path:'/account',component:account}, {path:'/goodslist',component:goodslist}, ] }) //将路由挂载到 Vue 实例中 var vm = new Vue({ el:'#app', render:c=>c(app), router })
-
注意:
// 因为.vue 文件的组件的中,有style的标签,所以要处理样式的loader {test:/\.css$/,use:['style-loader','css-loader']},
vue-router实现路由的嵌套
-
再建两个.vue 文件的子组件,并嵌套在account 路由下
-
在mian.js 中导入新建的两个子组件
// 导入 Account的两个子组件 import login from './suboom/login.vue' import register from './suboom/register.vue'
-
在account 路由对象中,添加children 属性,设置子路由,实现路由的嵌套
var router = new VueRouter({ routes:[ {path:'/account', component:account, children:[ {path:'login',component:login}, {path:'register',component:register}, ] }, {path:'/goodslist',component:goodslist}, ] })
组件中scoped属性和lang属性
-
样式的scoped 属性是通过css 的属性选择器实现的,因为一旦加了scoped属性,那么就回给这个组件的最外层的容器,添加一个data- 开头的属性,在渲染的时候,就只会选择这个属性。不会全局渲染。
//全局的字体都变成了红色 <style> div{ color:red; } </style> //只有当前组件的字体都变成了红色 <style scoped> div{ color:red; } </style>
-
普通的style 标签只支持普通的css样式,如果想要启用 scss 或 less ,需要为style 元素,设置lang属性
<style scoped lang="scss"> div{ font-style:italic; } </style>
Mint UI中按钮组件的使用
-
中文官方文档:http://mint-ui.github.io/#!/zh-cn
-
安装
cnpm install mint-ui -S
Promise 处理回调地狱问题
-
回调地狱,就是多层嵌套
// 顺序读取的 1 2 3 文件的内容 const fs = require('fs') const path = require('path') // 封装一个读取文件内容信息的方法 function getFileByPath(fpath, succCb, errCb) { fs.readFile(fpath, 'utf-8', (err, dataStr) => { if (err) return errCb(err) succCb(dataStr) }) } // 调用 getFileByPath 方法读取文件 getFileByPath(path.join(__dirname, './files/1.txt'), function (data) { console.log(data) getFileByPath(path.join(__dirname, './files/2.txt'), function (data) { console.log(data) getFileByPath(path.join(__dirname, './files/3.txt'), function (data) { console.log(data) }) }) })
-
Promise 是一个构造函数,表示异步操作。
var poromise = new Promise()
-
在Promise 上有两个函数
resolve // 成功之后的回调函数 resolve(决定) reject // 失败之后的回调函数 reject(拒绝)
-
Promise 是一个异步操作,所以,内部拿到操作结果后,无法使用return 把结果返回给调用者,,这个时候只能使用回调函数的形式,把成功或失败的的结果,返回给调用者
1、异步执行成功,需要在内部调用 成功的回调函数, resoleve 把结果返回给调用者 2、异步执行失败,需要在内部调用 失败的回调函数, reject 把结果返回给调用者
-
在Promise 构造函数的Prototype属性上,有一个.then()方法,也就是说,只要是Promise 构造函数创建的实例,都可以访问.then()方法。调用.then() 方法,为这个异步操作,指定成功(resolve) 和 失败(reject)回调函数
// 使用.then()方法 function getFileByPath(fpath) { var promise = new Promise(function(resolve,reject){ fs.readFile(fpath,'utf-8',(err,dataStr)=>{ if(err) return reject(err) resolve (dataStr) }) }) return promise// 放回promise对象 } //调用读取文件的方法 var p = getFileByPath("./files/1.txt") p.then(function(data){ console.log(data) },function(err){ console.log(err.message) } )
Promise 实例的创建,且创建就会立即执行
-
Promise 实例的创建
var promise = new Promise(function(){ fs.readFile('./files/1.txt','utf-8',(err,dataStr)=>{ if(err) throw err console.log(dataStr) }) })
-
Promise 的实例,一旦创建,就会立即调用,那么可以 创Promise 封装在一个function 中,调用function的时候在执行创建Promise 实例。
const fs = require('fs') // 封装一个读取文件内容信息的方法 function getFileByPath(fpath) { var promise = new Promise(function(){ fs.readFile(fpath,'utf-8',(err,dataStr)=>{ if(err) throw err console.log(dataStr) }) }) } //调用读取文件的方法 getFileByPath("./files/1.txt")
利用Promise 解决回调地狱的问题
-
对顺序读取多个文件,利用Promise,可以提高代码的可读性,和速度
// 使用.then()方法 function getFileByPath(fpath) { return new Promise(function (resolve, reject) { fs.readFile(fpath, 'utf-8', (err, dataStr) => { if (err) return reject(err) resolve(dataStr) }) }) } //调用读取文件的方法 getFileByPath("./files/1.txt") .then(function (data) { console.log(data) return getFileByPath('./files/2.txt') }) .then(function(data){ console.log(data) return getFileByPath('./files/3.txt') }) .then(function(data){ console.log(data) })
Promise 捕获异常
-
.them()方法里面有两个回调函数,一个是成功,resolve ,成功之后的回调函数 reject 失败之后的回调函数 ,在读取第一个文件的时候,以为没有13333.txe的文件,所以调用了失败的的回调函数,然后继续执行,读取文件2 ,和文件3 的内容。
//调用读取文件的方法 getFileByPath("./files/13333.txt") .then( function (data) {// 成功的回调函数 console.log(data)// 没有执行 return getFileByPath('./files/2.txt') }, function(err){ // 失败的的回调函数 console.log("这是失败的结果:"+err.message) return getFileByPath('./files/2.txt') } ) // 就算上的读取文件失败,也可以执行下面的代码 .then(function(data){ console.log(data)// 执行成功 return getFileByPath('./files/3.txt') }) .then(function(data){ console.log(data)// 执行成功 })
-
使用catch 捕获异常,在.then() 方法后面,加catch() 方法。如果在catch() 前面,有任何的Promise 执行失败,则立即终止所有的Promise 的执行,并马上进入catch 中去处理Promise 中抛出的异常。
//调用读取文件的方法 getFileByPath("./files/1.txt") .then(function (data) { console.log(data)// 执行成功 return getFileByPath('./files/3333.txt')//执行失败,进入catch 处理异常 },function(err){ console.log("这是失败的结果:"+err.message) // 不执行 return getFileByPath('./files/2.txt') }) .then(function(data){// 不执行 console.log(data) return getFileByPath('./files/3.txt') }) .then(function(data){// 不执行 console.log(data) }) .catch(function(err){// 执行 console.log("第二个文件读取失败:"+err.message) })
Promise-Jquery Ajax的使用
-
是用Promise 替代Ajax 成功的的方法
<script> $('input').on('click',function(){ $.ajax({ url:'./data.json', type:'get', dataType:'json', // success:function(data){ // console.log(data) // } }) .then(function(data){ console.log(data) }) }) </script>
s.readFile(fpath,‘utf-8’,(err,dataStr)=>{
if(err) throw err
console.log(dataStr)
})
})
}
//调用读取文件的方法
getFileByPath("./files/1.txt")
1.
## 利用Promise 解决回调地狱的问题
1. 对顺序读取多个文件,利用Promise,可以提高代码的可读性,和速度
```javascript
// 使用.then()方法
function getFileByPath(fpath) {
return new Promise(function (resolve, reject) {
fs.readFile(fpath, 'utf-8', (err, dataStr) => {
if (err) return reject(err)
resolve(dataStr)
})
})
}
//调用读取文件的方法
getFileByPath("./files/1.txt")
.then(function (data) {
console.log(data)
return getFileByPath('./files/2.txt')
})
.then(function(data){
console.log(data)
return getFileByPath('./files/3.txt')
})
.then(function(data){
console.log(data)
})
Promise 捕获异常
-
.them()方法里面有两个回调函数,一个是成功,resolve ,成功之后的回调函数 reject 失败之后的回调函数 ,在读取第一个文件的时候,以为没有13333.txe的文件,所以调用了失败的的回调函数,然后继续执行,读取文件2 ,和文件3 的内容。
//调用读取文件的方法 getFileByPath("./files/13333.txt") .then( function (data) {// 成功的回调函数 console.log(data)// 没有执行 return getFileByPath('./files/2.txt') }, function(err){ // 失败的的回调函数 console.log("这是失败的结果:"+err.message) return getFileByPath('./files/2.txt') } ) // 就算上的读取文件失败,也可以执行下面的代码 .then(function(data){ console.log(data)// 执行成功 return getFileByPath('./files/3.txt') }) .then(function(data){ console.log(data)// 执行成功 })
-
使用catch 捕获异常,在.then() 方法后面,加catch() 方法。如果在catch() 前面,有任何的Promise 执行失败,则立即终止所有的Promise 的执行,并马上进入catch 中去处理Promise 中抛出的异常。
//调用读取文件的方法 getFileByPath("./files/1.txt") .then(function (data) { console.log(data)// 执行成功 return getFileByPath('./files/3333.txt')//执行失败,进入catch 处理异常 },function(err){ console.log("这是失败的结果:"+err.message) // 不执行 return getFileByPath('./files/2.txt') }) .then(function(data){// 不执行 console.log(data) return getFileByPath('./files/3.txt') }) .then(function(data){// 不执行 console.log(data) }) .catch(function(err){// 执行 console.log("第二个文件读取失败:"+err.message) })
Promise-Jquery Ajax的使用
-
是用Promise 替代Ajax 成功的的方法
<script> $('input').on('click',function(){ $.ajax({ url:'./data.json', type:'get', dataType:'json', // success:function(data){ // console.log(data) // } }) .then(function(data){ console.log(data) }) }) </script>