这是我学习vue基础时候的笔记,在b站上跟着敲的,一开始是有道云笔记的形式,为了上传到博客整理了两个小时改成了markdown的形式,喜欢的点个赞,谢谢。
一. vue基本使用
1. 实例参数分析
el:元素的挂载位置(值可以是css选择器或者DOM元素) data:模型数据(值的一个对象)
2. 插值表达式用法 将数据填充到HTML标签中
插值表达式支持基本的计算操作
3. vue代码运行原理
分析概述编译过程中的概念(vue语法->原生语法)
4. 代码举例
<body>
<div id="box">
<div >
{{1+2}}
</div>
<div >
{{msg}}
</div>
</div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:'#box',
data:{
msg:'helloWorld'
}
})
</script>
</body>
二. Vue模板语法
1. 插值表达式{{}},可用来显示数据,计算数据
2. 指令
- 指令的本质就是自定义属性
- 指令的格式:以v-开始(如v-cloak)
v-cloak的用法
插值表达式存在闪动(插值表达式里面的vue代码显示出来,再渲染出了页面)的问题,使用v-cloak可以解决,解决原理:先隐藏,替换好值后再显示
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
[v-cloak]{
display: none;
}
</style>
</head>
<body>
<div id="box">
<!-- 可以完全编译好后再显示,插值不会出现闪动现象(先显示了vue的内容,再显示html的) -->
<div v-cloak>
{{1+2}}
</div>
<div v-cloak>
{{msg}}
</div>
</div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:'#box',
data:{
msg:'hello vue'
}
});
</script>
</body>
</html>
3. 数据绑定
3.1 v-text填充纯文本
3.2 v-pre 显示原始内容
3.3 v-html插入html片段
<div v-text="msg2">
<!-- 显示插入文本 hello vue -->
</div>
<div v-pre>
<!-- 显示原始的内容 {{msg}}-->
{{msg}}
</div>
<div v-html="msg1">
<!-- 插入html语句 显示带标签h1效果的内容 -->
</div>
var vm = new Vue({
el:'#box',
data:{
msg:'hello vue',
msg1:'<h1>HTML',
msg2:"hello vue"
}
});
4. 数据响应式
当vue对象里的data被修改时,页面也会发生改变
v-once
应用于显示的信息后续不需要修改时,可加这个属性,这样可以提高性能
<div v-text="msg2" v-once>
<!-- 插入文本 -->
</div>
5. 双向数据绑定
5.1 双向数据绑定
5.2 MVVM设计思想
- M(model)(对象,模型)
- V (view)(DOM,视图)
- vm(view-model)(vue) v->M需要vm使用DOM
- Listeners,vm->v需要vm使用Bindings, 从视图到模型用的是事件监听,从模型到视图用的是数据绑定
6. 事件绑定
6.1 v-on:指令
- v-on指令用法 加1
- v-on简写形式 <button type=“button” @click=“handle”>加1
- 事件函数的调用方法
- 直接函数名称 <button type=“button” @click=“handle”>加1
- 调用函数 <button type=“button” @click=“handle()”>加1
- 事件函数参数传递
- 普通参数和事件对象<button type=“button” @click="handle(“a”,“b”, e v e n t ) " 事 件 对 象 参 数 只 能 是 event)"事件对象参数只能是 event)"事件对象参数只能是event
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="box">
<div >
{{msg}}
</div>
<div>{{num}}</div>
<button type="button" @click="handle">加1</button>
<button type="button" @click="handle2(1,3,$event)">加法运算</button>
</div>
<script type="text/javascript" src="vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:'#box',
data:{
msg:'hello vue',
num:0
},
methods:{
handle:function(){
this.num++;
},
handle2:function(a,b,event)
{
console.log(event.target.innerHTML);
var sum=a+b;
console.log('a+b='+sum);
}
}
});
</script>
</body>
</html>
事件修饰符(可以连写,要注意顺序)
- .stop-调用 event.stopPropagation()。阻止冒泡事件发生
- .prevent - 调用 event.preventDefault()。阻止默认事件发生
- .capture - 添加事件侦听器时使用 capture 模式。
- .capture - 添加事件侦听器时使用 capture 模式。
- .{keyCode | keyAlias} - 只当事件是从特定键触发时才触发回调。
- .native - 监听组件根元素的原生事件。
- .once - 只触发一次回调。
- .left - (2.2.0) 只当点击鼠标左键时触发。
- .right - (2.2.0) 只当点击鼠标右键时触发。
- .middle - (2.2.0) 只当点击鼠标中键时触发。
- .passive - (2.3.0) 以 { passive: true } 模式添加侦听器
<button type="button" v-on:click.stop="handle1">加1</button>
<!-- .stop阻止冒泡 -->
<a href="http://www.baidu.com" @click.prevent='handle2'>百度
<!-- .prevent阻止默认事件,a标签不会跳转 -->
</a>
按键修饰符
- v-on:keyup.delete=’ ’
- v-on:keyup.enter = ‘’
- config.keyCodes 对象自定义按键修饰符别名:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
</style>
</head>
<body>
<div id="box">
用户名:<input type="text" name="" id="" value="" v-model='user' v-on:keyup.delete="clear"><br>
密码:<input type='password' name="" id="" value="" v-model='pwd' v-on:keyup.enter="Submit">
<br />
密码:<input type='password' name="" id="" value="" v-model='pwd' v-on:keyup.aaa="handle1">
<input type="submit" id="" name="" value="登陆" @click="handle1" />
</div>
<script src="vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// 自定义按键修饰符:名字可以随便,对应按键的code值
Vue.config.keyCodes.aaa = 65
var vm = new Vue({
el: '#box',
data: {
user: '',
pwd: ''
},
methods: {
handle1: function (event) {
console.log(this.user, this.pwd)
console.log(event.keyCode);
},
Submit: function () {
console.log(this.user, this.pwd)
},
clear: function () {
this.user = ' ';
}
}
})
</script>
</body>
</html>
7.属性绑定
7.1 v-bind:指令 缩写:
v-model底层原理本质
v-bind:value=‘msg’,v-on:input’‘msg=$event.target.value’
<body>
<div id="box">
<a :href="url">百度</a>
<button type="button" @click="change">改变</button>
</div>
<script src="vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
var vm = new Vue({
el:'#box',
data:{
url:'http://www.baidu.com'
},
methods:{
change:function(){
this.url='https://www.bilibili.com/video/av50680998/?p=213'
}
}
})
</script>
</body>
8.样式绑定
class样式处理
- 对象语法 :class = “{active:isactive,error:iserror}”
- 数组语法:class = “[a,b]”
简写 :class = “a”,默认的class = “xxx” 会保留
style样式处理
- 对象语法:style="{color:activeColor,fontSize:fontsize}"
- 数组语法:style= “[a,b]”
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
.active{
border: 1px solid red;
width: 100px;
height: 100px;
}
.error{
background-color: yellow;
}
.test{
color: #0000FF;
}
</style>
</head>
<body>
<div id="box">
<div id="app" v-bind:class="{active:isactive,error:iserror}">
样式绑定
</div>
<div><button type="button" @click="handle">对象语法改变</button></div>
<!-- 对象绑定和数组绑定结合使用 -->
<div id="app2" v-bind:class="[a,b,{test:istest}]">
样式绑定
</div>
<div><button type="button" @click="handle2">数组改变</button></div>
<!-- 简化操作 -->
<div id="app3" v-bind:class="arr">
样式绑定
</div>
<div><button type="button" @click="handle3">数组简化操作</button></div>
<div id="app4" v-bind:class="obj">
样式绑定
</div>
<div><button type="button" @click="handle4">对象简化操作</button></div>
<div id="app5" v-bind:style="{color:activeColor,fontSize:fontsize}">
样式绑定
</div>
<div><button type="button" @click="handle5">style样式处理</button></div>
<div id="app6" v-bind:style="[basestyle,fugai]">
样式绑定
</div>
</div>
<script src="vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
var vm = new Vue({
el:'#box',
data:{
activeColor:'red',
fontsize:'28px',
isactive:true,
iserror:true,
a:'active',
b:'error',
istest:true,
arr:['active','error'],
obj:{
active:true,
error:true,
},
basestyle:{
color:'blue',
fontSize:'30px',
},
fugai:{
border:'1px solid red',
color:'pink'
}
},
methods:{
handle:function(){
this.isactive=!this.isactive
},
handle2:function()
{
this.a='',
this.b=''
},
handle3:function()
{
Vue.set(this.arr,0,'')
},
handle4:function()
{
this.obj.active = !this.obj.active
},
handle5:function()
{
this.activeColor='blue';
}
}
})
</script>
</body>
</html>
9.分支循环
分支结构
- v-if
- v-else
- v-else-if
- v-show
v-if与v-show的区别
- v-if控制元素是否渲染页面
- v-show控制元素是否显示(已经渲染到页面)
循环结构
- v-for遍历数组 v-for = “(item,index) in arr”
- key的作用:帮助区分不同元素,提高性能
- v-for遍历对象(v-for=’(value,key,index)’ in object )
- v-if和v-for结合使用
三.vue常用特性
常用特性概述
- 表单操作
- 自定义指令
- 计算属性
- 过滤器
- 侦听器
- 生命周期
表单操作
基于vue的表单操作
- input
- textarea
- select
- radio
- checkbox
表单域修饰符
- number:转化为数值 如(v-model.number=’’)
- trim:去掉开始和结尾的空格
- lazy:将input事件切换为change事件
自定义属性directives
- 自定义指令的语法规则(获取元素焦点)
- 自定义指令用法(例子 v-focus)
- 带参数的自定义指令(改变元素背景色)
- 指令的用法(v-color=’{color:“orange”}’)
- 局部指令(使用在组件内)
<div id="app">
<input type="text" v-color='msg'>
<!-- 携带参数的 -->
<input type="text" v-focus>
</div>
------------------------------------------
directives:{
color:{
inserted: function(el,binding)
{
console.log(binding);
el.style.backgroundColor = binding.value.color;
}
},
focus:{
inserted:function(el)
{
el.focus()
}
}
}
计算属性computed
应用于负责的计算,计算属性可以使模板更加简洁
<div>{{rever}}</div>
// 直接调用
--------------------------------
computed:{
rever:function()
{
return this.msg.split('').reverse('').join('');
//分割数据,然后反转,拼接
}
}
计算属性和方法的区别
- 计算属性使基于他们的依赖进行缓存(多次使用同一个计算属性只会计算一次)
- 方法不存在缓存,每次调用都要重新执行
侦听器watch
- 运用于数据变化时执行异步操作或开销较大的操作
- 侦听器用法
<div id="app">
<span>用户名:</span>
<span >
<input type="text" v-model.lazy="uname">
</span>
<span>
{{tip}}
</span>
</div>
<script src="vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
var vm = new Vue(
{
el:'#app',
data:{
tip:'',
uname:''
},
methods:{
cheack:function(uname)
{
var that = this;
setTimeout(function(){
if(uname=='admin')
{
that.tip = '用户名已存在'
}
else
{
that.tip = '用户名可以使用'
}
},1000)
}
},
watch:{
uname:function(val)
{
this.cheack(val);
this.tip = '正在验证...'
}
}
})
</script>
过滤器
过滤器的作用
格式化数据,比如将字符串格式化首字母大写,时间格式化
自定义过滤器(例子为全局定义) f第一个参数默认为你需要处理的数据
Vue.filter('过滤器名称', function(val){
// 过滤器业务逻辑
})
过滤器的使用
<div>{{msg | upper}}</div>
<div>{{msg | upper | lower}}</div>
<div v-bind:id="id | formatId"></div>
局部过滤器(filters)
// 写在组件里
filters:{
upper:function(val)
{
return val.charAt(0).toUpperCase() + val.slice(1);
}
}
带参数的过滤器(第二个参数开始为传入)
生命周期
主要阶段
- 挂载(初始化相关属性)
- beforeCreate 实例初始化后,数据观测和事件配置之前被调用
- created 实例创建完成之后调用
- beforeMount 挂载开始之前被调用
- mounted:被心创建的vm。$el替换,并挂载到实例上去之后调用该钩子
- 更新(元素或组件的变更操作)
- beforeUpdat 数据更新时调用,发生在虚拟DOM打补丁之前
-updated 由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子
销毁(销毁相关属性) - beforeDestroy 销毁实例之前
- destroyed 销毁后调用
- beforeUpdat 数据更新时调用,发生在虚拟DOM打补丁之前
四 补充数组相关的api
变异方法(修改原有的数据)
- push() 数组最后添加内容
- pop() 弹出数组最后一个 这两个为栈
- shift() 头部弹出
- unshift() 头部插入 这两个为队列
- splice(index) 删除由index开始后面的元素
- splice(index,num) 由index开始删除num个元素 - splice(index,index2,‘apple2’);由index开始删除,并在index处添加apple2
- sort() 排序
- reverse() 翻转
替换数组(生成新数组,原有数据不改变)
- filter(fn) 过滤
- concat()连接两个或多个数组。
- slice(index,index2) index到index2中的元素形成新数组替换旧数组;
修改响应式数据
Vue.set(vm.item,indexOfitem,newValue)
第一个参数表示要处理的数组名,第二个要处理的数组的索引,第三个是数组的设置值
- Vue.set(vm.list,2,‘lemon’)修改vm中list数组index为2的值为lemon
- vm.$set(vm.list,1,‘lemon’)与上面相似
- vm.$set(vm.list,‘sex’,‘man’)往list中添加sex属性并赋值man
五. 组件
全局组件注册语法
Vue.component(组件名称,{
data:组件数据(data 必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供 data 函数,每次创建一个新实例后,我们能够调用 data 函数,从而返回初始数据的一个全新副本数据对象。)
template:' '组件模板内容,
methods:{ }......
})
Vue.component('button-counter',{
data:function(){
return {
count:0
}
},
template:`<div>
<button @click="count++">点击了{{count}}次</button>
<button>测试</button>
</div>`
})
组件用法
直接引入组件的名称作为标签,每个都是相互独立的,互不干扰
<div>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
组件注册注意事项
- data必须是一个函数
- 组件模板内容必须时单个跟元素(模板里面一个div套着所有的内容)
- 组件模板内容可以时模板字符串
组件命名 - 驼峰命名(如果使用驼峰式命名组件,那么在使用组件的时候,只能在字符串模板中用驼峰的方式使用组件,但是在普通标签模板中,必须使用短横线的方式使用组件,因为html不识别大小写)
- 横杠(‘button-counter’)(推荐使用)
局部组件注册
<div id="#app">
<hello-world></hello-world>
</div>
//局部组件注册
var helloworld = {
data:function()
{
return {
msg:'helloworld'
}
},
template:'<div>{{msg}}</div>'
}
// 局部组件只能在注册他的父组件中使用
var vm = new Vue(
{
el:'#app',
data:{
},
components:{
'hello-world':helloworld,、
}
})
组件间数据交互
父组件向子组件传值
- 组件内部通过pros接收传递过来的值
Vue.component('brother-com',
{
// 父组件传过来的属性
props:['title'],
data:function()
{
return {
test:'子组件的内容'
}
},
template:`
<div>{{test + '---' +title}}</div>`
})
- 父组件通过属性将值传递给子组件
<!-- 静态绑定 -->
<brother-com title='来自父组件的值'></brother-com>
<!-- 动态属性绑定 -->
<brother-com :title='pmsg'></brother-com>
// 父组件
var vm = new Vue({
el:'#app',
data:{
pmsg:'来自父组件的内容'
}
})
- props属性名规则
- 在props中使用驼峰形式,模板中需要使用短横线形式
- 字符串形式的模板中没有这个限制
props属性值类型(string,Number,Boolean,array,Object)
子组件向父组件传递数据
和事件委托差不多,子组件的事件委托给父组件,子组件调用申明方法,父组件监听到,父组件执行父组件对应的方法。
props传递数据原则:单向数据流(虽然可以直接改变props的属性值来修改父组件的
- 子组件通过自定义事件向父组件传递信息
Vue.component('brother-com',
{
props:['title','pnum','pmsgb','parr','pobj'],
template:
`
<div>
// 子组件模板通过$emit('事件名')定义事件
<button @click="$emit('change-fa',100)">点击改变字体大小</button>
</div>
`
})
- 父组件监听子组件的事件\
事件对象参数 event 的处理。不加括号时,函数第一个参数为 event,加了括号后,需要手动传入 $event 才能获得事件对象。
<div id="app">
<brother-com @change-fa='handle($event)' ></brother-com>
</div
// 父组件处理数据
var vm = new Vue({
el:'#app',
data:{
},
methods:{
handle:function(val)
{
this.size +=val;
}
}
})
非父子组件间的传值
- 单独的事件中心管理组件间的通信 (单独new一个vue对象作为事件中心)
var eventHub = new Vue()
- 设置监听事件($on)
//2. 监听事件,可以提供给兄弟组件调用,可以自己用
eHub.$on('tomFn', (val) => {
this.num++
})
- 调用兄弟事件
// 调用兄弟组件的方法
eHub.$emit('jerryFn',1)
- 销毁事件
// 销毁jerryfn
eHub.$off('jerryFn')
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id='app'>
<div>父组件</div>
<div>
<button @click="handle">销毁</button>
</div>
<test-jerry></test-jerry>
<test-tom></test-tom>
</div>
<script src="vue.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
//提供事件中心
var hub = new Vue();
Vue.component('test-tom',{
data:function(){
return {
num:0
}
},
template:`
<div>
<div>TOM:{{num}}</div>
<div>
<button @click='handle'>点击</button>
</div>
</div>
`,
methods:{
handle:function()
{
//触发兄弟事件
hub.$emit('jerry-event',2);
}
},
mounted:function(){
//监听事件,开启tom事件,可以提供给兄弟触发
hub.$on('tom-event',(val)=>{
this.num+=val;
});
}
})
Vue.component('test-jerry',{
data:function(){
return {
num:0
}
},
template:`
<div>
<div>jery:{{num}}</div>
<div>
<button @click='handle'>点击</button>
</div>
</div>
`,
methods:{
handle:function()
{
//触发兄弟组件的事件
hub.$emit('tom-event',1);
}
},
mounted:function(){
//监听事件,开启jerry的事件
hub.$on('jerry-event',(val)=>{
this.num+=val;
});
}
})
var vm = new Vue({
el:'#app',
data:{
},
methods:{
handle:function()
{
//销毁tom事件,这样兄弟jerry无法继续开始点击事件了
hub.$off('tom-event')
}
}
})
</script>
</body>
</html>
组件插槽的作用
父组件向子组件传递内容
<test>{{err}}</test> //err的值为slot的内容
Vue.component('test',{
template:`
<div>
<strong>ERROR:</strong>
// 子组件中放置slot作为插槽,父组件的内容在这里展示
<slot></slot>
</div>
`
})
具名插槽
// 具名插槽的两种使用
<test>
// 有name的就对应name的位置地方
<p slot='foot'></p>
<p><p>
</test>
<test>
<template slot = 'foot'>
<p></p>
<p><p>
</template>
</test>
Vue.component('test',{
template:`
<div>
<strong>ERROR:</strong>
// 子组件中放置slot作为插槽,父组件的内容在这里展示
<slot></slot>
<slot name='foot'></slot>
</div>
`
})
六前后端交互模式
接口调用方式
- 原生ajax
- 基于jQuery的ajax
- fetch
- axios
Promise用法
异步调用
- 异步效果分析
- 定时任务
- ajax
- 事件函数
- 多种异步调用的依赖分析
- 多次异步调用的结果顺序不确定
- 异步调用结果如果存在依赖需要嵌套
Promise概述
Promise是异步编程的一种解决方案,从语法上讲,Promise是一个对象,从它可以获取异步操作的消息。
使用promise的好处
- 可以避免多层异步调用嵌套问题(回调地狱)
- Promise对象提供简洁的API,使得控制异步操作更加容易
Promise基本用法
- 实例化Promise对象,构造函数中传递函数,该函数中用于处理异步任务
- resolve和reject两个参数用于处理成功和失败两种情况,并通过p.then获取处理结果
// 成功是调用resolve,失败时调用reject
var p = new Promise(function(resolve,reject)
{
//这里用于实现异步任务
setTimeout(function(){
var flag=false;
if(flag)
{
//正常情况
resolve('hello');
}
else
{
//异常情况
reject('出错了');
}
},100);
})
p.then(function(data){//接收正常情况
console.log(data)
},function(info){//接收错误情况
console.log(info)
})
基于Promise处理ajax请求
function queryData(url)
{
return new Promise(function(resolve,reject){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState!=4)return;
//==4表示接收结果完毕,status==200表示处理的结果是正确的
if(xhr.readyState==4&&xhr.status==200)
{
//处理正常的情况
resolve(xhr.responseText);
}
else{
reject('服务器错误')
}
};
xhr.open('get',url);
xhr.send(null);
});
}
发送ajax请求
queryData('http://rap2api.taobao.org/app/mock/251796/crms/crmsAdmin/getUnList')
.then(function(data){
console.log(data);
return queryData('http://rap2.taobao.org:38080/repository/get?id=:repositoryId')
//直接返回了一个新的Promise对象
})
//这个data得到上一个异步的结果
.then(function(data){
return new Promise(function(resolve,reject)
{
setTimeout(function(){
resolve(123);
},1000)
})
})
//同理这个data得到上一个异步的结果,返回123
.then(function(data){
return 'hello'//返回了普通值,这个then会自动产生一个默认的promise对象,保证下一个then采取链式操作
})
.then(function(data){
console.log(data) //hello
})
then参数中的函数返回值
- 返回Promise实例对象
- 返回的该实例对象会调用下一个then
- 返回普通值
- 返回的普通值会直接传递给下一个then,通过then参数中函数的参数接收该值
Promise常用的API
- 实例方法
- p.then()得到异步任务的正确结果
- p.catch()获取异常信息
- p.finally()无论成功与否都会执行
- 对象方法
- Promise.all()并发处理多个异步任务,所有任务都会执行完成才能得到结果
- Promise.race()并发处理多个异步任务,只要有一个任务完成就能得到结果
var a=querydata('http://rap2.taobao.org:38080/app/mock/241938/mock/19/api/admin/greenhouse/list/:id')
var b=querydata('http://rap2.taobao.org:38080/app/mock/241938/mock/19/api/admin/greenhouse/list/:id')
var c=querydata('http://rap2.taobao.org:38080/app/mock/241938/mock/19/api/admin/greenhouse/list/:id')
// 得到一个数组
// Promise.all([a,b,c]).then(function(data){
// console.log(data)
// })
//只打印最先返回的结果,但是其他异步的结果也在进行
Promise.race([a,b,c]).then(function(data){
console.log(data)
})
接口调用fetch用法
// fetch api 基本用法
fetch('http://rap2.taobao.org:38080/app/mock/241938/mock/19/api/admin/greenhouse/list/2')
.then(function(data){
//text()方法属于fetchapi的一部分,它返回一个promise实例对象,用于后台返回的数据,字符串,想获取值需要转换成json
// return data.text();
// 返回的是对象
return data.json();// ==JSON.parse(data)
})
//此处才是获取最终数据
.then(function(data){
//text方式需要转化成对象才能访问属性
// var obj = JSON.parse(data);
// console.log(obj)
//json方式可直接属性
console.log(data)
})
请求参数
- 常用配置选项
- method(string) :HTTP请求方法,默认为GET
- body(Stirng);HTTP的请求参数
- headers(Object):请求头,默认为{}
fetch('url',
{methods:'post',
// body:JSON.stringify({uname:'lisi',age:12})
body:'uname=list&pwd=123'),
headers:{'xxx':xxx}})
.then(function(data){
return data.text()
})
.then(ret=>{
console.log(ret)
})
axios
aixos基本特性
- 支持浏览器和node.js
- 支持promise
- 能拦截请求和响应
- 自动转换json数据
基本用法
axios.get('url')
.then(function(ret){
//data属性使固定的用法
console.log(ret.data)
})
axios的参数传递
- get传递参数(与delete一样)
- 通过URL传递参数
- 通过params选项传递参数
//通过url传递参数
axios.get('url?id=123')
.then(function(ret){
//data属性使固定的用法
console.log(ret.data)
})
axios.get('url/123')
.then(function(ret){
//data属性使固定的用法
console.log(ret.data)
})
// 通过params
axios.get('/adata',{
params:{
id:123,
name:'ljx'
}
}).then(ret=>{
console.log(ret.data)
})
2.post参数传递(put类似)
- 通过选项传递参数(默认传递的是json格式)
- 通过URLSearchParams传递参数
// 选项传递参数
axios.post('/adata',{
uname:'tom',
pwd:123
})
.then(function(ret){
console.log(ret.data)
})
var params = new URLSearchParams()
params.append('uname','zhangsan')
axios.post('/adata',params).then(ret=>{
console.log(ret.data)
})
axios响应结果
- data:实际响应回来的数据
- headers:响应头信息
- status:响应状态码
- statusText:响应状态信息
axios全局配置
axios.defaults.timeout = 3000 // 超时时间
axios.defaults.baseURL 默认地址
axios.defaults.headers[‘mytoken’] = ‘’ 设置请求头
拦截器
//asios请求拦截器
axios.interceptors.request.use(function(config){
console.log(config.url)
config.headers.mytoken='nihao'
return cofig;
},function(err){
console.log(err)
})
//响应拦截器(设置好时调接口就能直接拿到data了,不再是数据对象)
axios.interceptors.response.use(function(ret){
//这里对返回的数据进行处理
var data = res.data;
return data;
},function(err){
console.log(err)
})
async/await
基本用法
- async/awai 是es7引入的新语法,可以更加方便进行异步操作
- async关键字用于函数上(async函数的返回值是promise实例对象)
- await关键字用于async函数当中(await可以得到异步的结果)
七路由
路由的基本概念与原理
- 后端路由
- 概念:根据不同的用户URL请求,返回不同的内容
- 本质:URL请求地址与服务器资源之间的对应关系
- spa(Single Page Application)
- 后端渲染(存在性能问题)
- Ajax前端渲染(前端渲染提高性能,但是不支持浏览器的前进后退操作)
- Spa(Single Page Application)单页面应用程序:整个网站只有一个页面,内容的变化通过ajax局部更新实现,同时支持浏览器地址栏的前进和后退操作
- SPA实现原理之一:基于URL地址的hash(hash的变化会导致浏览器记录访问历史的变化,但是hash的变化不会触发新的URL请求)
- 在实现SPA过程中,最核心的技术就是前端路由
- 前端路由
- 根据不同的用户事件,显示不同的页面的内容
- 本质:用户事件与事件处理函数之间的对应关系
Vue Router
- 支持hash模式或html5模式
- 支持嵌套路由
- 支持路由参数
- 支持编程式路由
- 支持命名路由
vue-router的基本使用
- 引入相关库
<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
<script src="./vue-router.js" type="text/javascript" charset="utf-8"></script>
- 添加路由链接
<!-- router-link是vue中提供的标签,默认会被渲染为a标签 -->
<!-- to 属性默认会被渲染为href属性 -->
<!-- to属性的值会被渲染为#开头的hash地址 -->
<router-link to="/user">User</router-link>
<router-link to="/register">Register</router-link>
- 添加路由填充位
<!-- 路由占位符 -->
<router-view></router-view>
- 定义路由组件
const User = {
template:'<h1>User组件</h1>'
}
const Register = {
template:'<h1>Register组件</h1>'
}
- 配置路由规则并创建路由实例
//创建路由实例对象
const router = new VueRouter({
//所有路由规则
routes:[
//需要被重定向的地址,redirect跳到新地址
{path:'/',redirect:'/register'},
{
path:'/user',component:User
},
{
path:'/register',component:Register
}
]
})
- 把路由挂载到Vue跟实例中
const vm = new Vue({
el:'#app',
data:{},
//挂载路由实例对象
router:router
})
路由重定向
用户在访问地址A的时候,强制调转到地址c从而展示特定的组件页面
嵌套路由
- 嵌套路由功能分析
- 点击父级路由链接显示模板内容
- 模板内容又有子级路由链接
- 点击子级路由链接显示子级模板内容
- 父级路由模板
- 父级路由链接
- 父组件路由填充位
<router-link to="/user">User</router-link>
<router-link to="/register">register</router-link>
<router-view></router-view>
- 子路由模板
- 子路由链接
- 子路由
const Register ={
template:`
<div><h1>register组件</h1>
<hr/>
<router-link to="/register/tab1">tab1</router-link>
<router-link to="/register/tab2">tab2</router-link>
<router-view></router-view>
</div>
`,
}
- 嵌套路由配置
- 父级路由通过children属性配置子级路由
{path:'/register',component:Register,
//通过children属性添加子路由
children:[
{path:'/register/tab1',component:Tab1},
{path:'/register/tab2',component:Tab2}]
}
动态路由匹配
动态路由匹配的基本用法(不太灵活)
<router-link to="/user/1">User1</router-link>
<router-link to="/user/2">User2</router-link>
<router-link to="/user/3">User3</router-link>
<router-link to="/register">register</router-link>
<router-view></router-view>
const User={
//路由组件中通过$route.param 获取路由参数
template:`<h1>User--用户id为:{{$route.params.id}}</h1>`
}
//动态路径参数,以冒号开头
routes:[{path:'/user/:id',component:User}]
路由组件传递参数
路由组件传递参数
$route与对应路由形成高度耦合,不够灵活,所以可以使用props将组件和路由解耦
- props值为布尔类型
const router = new VueRouter({
routes:[
// 如果props设置为true,route.params将会被设置为组件属性
{path:'user/:id',component:User,props:true}
]
})
const User = {
props:['id'],// 使用props接收参数,例子中获取到的是id
template:'<div>用户ID:{{id}}</div>' // 使用路由参数
}
2.props的值为对象类型
const route = new VueRouter({
routes:[
// 如果props是一个对象,他会按原样设置成组件属性
// 此时id只能通过$route.param来获取,props只有uname和age
{path:'/user/:id',component:User,props:{uname:'lisi',age:12}}
]
})
const User = {
props:['uname','age'],
template:`<div>用户信息:{{uname,age}}`
}
3.props的值为函数类型
const route = new VueRouter({
routes:[
// 如果props是一个函数,则这个函数接收route对象为自己的形参
{path:'/user/:id',component:User,props:route=>({uname:'lisi',age:12,id:route.params.id})}
]
}
const User = {
props:['uname','age','id'],
template:`<div>用户信息:{{uname age id}}`
}
命名路由
<router-link :to="{name:'user',params:{id:2}}">User</router-link>
const User = {
props:["id",'uname','age'],
template:`
<div>
<h1>User--用户id{{id}}姓名{{uname}}年龄{{age}}</h1>
<button @click='turn'>跳转到register</button>
</div>`,
methods:{
turn(){this.$router.push('/register')}
}
}
const Register = {
template:`
<div>
<h1>Register组件</h1>
<button @click='goback'>返回上一个页面</button>
</div>`,
methods:{
goback(){
this.$router.go(-1);
}
}
}
routes:[
{
//命名路由
name:'user',
path:'/user/:id',
component:User,
props:route=>({name:'heihei',age:20,id:route.params.id})
},
编程式导航
当你点击 时,这个方法会在内部调用,所以说,点击 等同于调用 router.push(…)。
声明式 | 编程式 |
---|---|
router.push(…) |
编程式导航的基本用法
- this.$router.push(‘hash地址’)
- this.$router.go(n) 0刷新,1前进,-1后退
编程式导航的基本用法
this. r o u t e r . p u s h ( ′ h a s h 地 址 ′ ) t h i s . router.push('hash地址') this. router.push(′hash地址′)this.router.go(n) 0刷新,1前进,-1后退
// 字符串(路径名称)
router.push('/home')
// 对象
router.push({path:'/home'})
// 命名的路由(传递参数)
router.push({name:'/user',params:{userId:123}})
// 带查询参数 /user?userId=123
router.push({path:'/user',query:{userId:123}})
八模块化
模块化概述
传统开发的主要问题:
- 命名冲突
- 文件依赖
通过模块化解决上述问题 - 模块化就是把单独的一个功能封装到一个模块中,模块之间相互隔离,但是可以通过特定的接口公开内部成员,也可以依赖别的模块
- 模块化的好处:方便代码的重用,从而提升开发效率,并且方便后期的维护
浏览器端的模块规范
- AMD
require.js - CMD
sea.js
落伍了,有更好的规范
服务器端模块化规范
- commonJS
- 模块分为单文件模块与包
- 模块成员导出:module.exports和exports
- 模块成员导入:require(‘模块标识符’)
大一统的模块化规范-es6模块化
ES6模块化规范中定义
- 每个js文件都是独立模块
- 导入模块成员使用import关键字
- 暴露模块成员使用export关键字
- Node.js中通过babel体验ES6模块化
Babel 是一个工具链,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。下面列出的是 Babel 能为你做的事情:
- 语法转换
- 通过 Polyfill 方式在目标环境中添加缺失的特性 (通过 @babel/polyfill 模块)
- 源码转换 (codemods)
安装下载
- npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/node
- npm install --save @babel/polyfill
- 项目根目录创建文件 babel.config.js
- babel.config.js文件内容如图
const presets = [
["@babel/env",{
targets:{
edge:'17',
firefox:'60',
chrome:'67',
safari:'11.1'
}
}]
]
module.exports = {presets}
- 通过npx babel-node index.js执行代码
ES6模块化的基本语法
- 默认导出与默认导入
- 默认导出语法 export defaulr 默认导出的成员
//默认导出
// 定义私有成员
let a = 10
let c = 20
function happy(){}
// 外界访问不到d,因为没有暴露出去
// 将本模块的私有成员暴露出去,供其他模块使用
export default{
a,
c,
happy
}
- 默认导入的语法 import 接收名称from’'模块表示符号 注意:每个模块中,只允许使用唯一的一次export default,否则报错
//导入模块成员 , 用m1接收
import m1 from './m1export.js'
console.log(m1)
2.按需导出与按需导入
- 按需导出语法 export let s1=10
export let s1=10
export let s2=10
export function say = function(){}
- 按需导入语法
import {s1,s2 }from './m1export.s'
//s1,s2必须要导入文件里有的
3.直接导入并执行模块代码 只想单纯执行某个模块中的代码,并不需要得到模块中向外暴露的成员时使用
//当前文件模块 m2.js
// 在当前模块中执行一个for循环操作
for(let i=0;i<3;i++){
console.log(i)
}
// 其他文件导入
import './m2.js'
webpack
当前web开发面临的困境
- 文件依赖关系错综复杂
- 静态资源请求效率低
- 模块化支持不友好
- 浏览器对高级JavaScript特性兼容程度较低
- 其他
webpack的基本使用
是一个前端项目构建工具(打包工具),提供友好的模块化支持,以及代码压缩混淆,处理js兼容问题,性能优化等
- 创建列表隔行变色项目
- 新建项目空白目录,运行npm init -y命令,初始化包管理配置文件package.json
- 新建src源代码目录
- 新建src->index.html首页
- 初始化首页基本结构
- 运行npm install jquery -S 命令,安装jQuery
- 通过模块化的形式,实现列表隔行变色的效果
- 在项目安装和配置webpack
- 运行npm install webpack webpack-cli -D命令安装webpack相关包
- 在项目根目录创建webpack.config.js的webpack配置文件
- 在webpack的配置文件中,初始化一下基本配置
module.exports = {
mode:'development' // mode用来指定构建模式,开发模式不会压缩代码
}
- 在package.json配置文件中的script节点下,新增dev脚本如下:
"scripts":{
"dev":"webpack" //script节点下的脚本,可以通过npm run dev运行
}
在终端运行npm run dev,启动webpack项目打包
3.配置打包的入口与出口
webpack 的默认约定:
- 打包的入口文件为src ->index.js
- 打包的输出文件为dist ->main.js
如果需要修改打包的入口和出口,可以在webpack.config.js中新增如下的配置信息
const path = require('path')
module.exports = {
mode : "development", // development production
//__dirname 项目根路径+入口文件
entry: path.join(__dirname,'./src/index.js'),
output:{
path:path.join(__dirname,'./dist'),// 输出文件的存放路径
filename:'bundle.js' // 输出文件的名称
}
}
- 配置webpack的自动打包功能
- 运行npm install webpack-dev-server -D 命令,安装支持项目自动打包的工具
- 修改package.json ->scripts中的dev命令如下:
"scripts":{
"dev":"webpack-dev-server"//script节点下的脚本,可以通过npm run运行
}
- 将src->index.html中,script脚本的引用路径,修改为"./bundle.js
- 运行那个npm run dev命令,重新进行打包
- 在浏览器中访问 http://localhost:8080地址,查看自动打包效果
注意: - webpack-dev-server 会自动启动一个实时打包的http服务器
- webpack-dev-server打包生成的输出文件,默认放到项目根目录中,而且是虚拟,看不到的
- 配置html-webpack-plugin生成预览页面
- 运行npm install html-webpack-plugin -D 命令,安装生成预览页面的插件
- 修改webpack.config.js文件头部区域,添加如下配置
// 导入生成预览页面的插件,得到一个构造函数
const HtmlWebpackPlugin = require('html-webpack-plugin')
const htmlPlugin = new HtmlWebpackPlugin({
template:'./src/index.html', // 指定用到的模板文件
filename:'index.html' //指定生成的文件名称,存在内存中,目录上不显示
})
module.exports = {
plugins:[htmlPlugin] //plugins数组是webpack打包期间会用到的一些插件列表
}
- 修改webpack.config.js文件向外暴露的配置对象,新增配置节点
module.exports = {
plugins:[htmlPlugin] //plugins数组是webpack打包期间会用到的一些插件列表
}
- 配置自动打包相关的参数
// package.json中配置
// --open 打包完成后自动打开浏览器页面
// --host 配置IP地址
// --port配置端口
"scripts":{
"dev":"webpack-dev-server --open --host 127.0.0.1 --port 8888"
}
webpack中的加载器
- 通过loader打包非js模块 和node里的gulp差不多。
在实际开发过程中,webpack默认只能打包处理以.js后缀名结尾的模块,其他非.js后缀名结尾的模块,webpack默认处理不了,需要调用loader加载器才可以正常打包
loader加载器可以协助webpack打包处理待定的文件模块,如
- less-loader可以打包处理 .less相关文件
- sass-loader 可以打包处理.scss相关的文件
- url-loader处理css中url路径相关的文件
webpack中的加载器的基本使用
- 打包处理css文件
- 运行npm i style-loader css-loader -D 命令,安装处理css文件的loader
- 在webpack.config.js中module->rules数组中,添加loader规则如下
// 所有第三方文件模块匹配规则
module: {
rules: [{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
//test表示匹配类型的文件,use表示调用的loader
//注意:
//use的顺序是固定的,必须先style-loader,再css-loader
// 多个loader的调用顺序是从后往前调用
]
}
- 打包处理less文件
- 运行npm i less-loader less -D命令
- 在webpack.config.js中module->rules数组中,添加loader规则如下
// 所有第三方文件模块匹配规则
module: {
rules: [{
test: /\.less$/,
use: ['style-loader', 'css-loader','less-loader']
}
//test表示匹配类型的文件,use表示调用的loader
//注意:
//use的顺序是固定的,必须先style-loader,再css-loader
// 多个loader的调用顺序是从后往前调用
]
}
- 打包处理scss文件
- 运行npm i scss-loader node-sass -D命令
- 在webpack.config.js中module->rules数组中,添加loader规则如下
// 所有第三方文件模块匹配规则
module: {
rules: [{
test: /\.scss$/,
use: ['style-loader', 'css-loader','scss-loader']
}
]
}
- 配置postCSS自动添加css兼容前缀
- npm i postcss-loader autoprefixer -D
- 在项目根目录创建postcss的配置文件 postcss.config.js
const autoprefixer = require("autoprefixer")
module.exports = {
plugins:[autoprefixer]
}
- 在webpack.config.js 的module->rules数组中,修改css的loader规则
// 所有第三方文件模块匹配规则
module: {
rules: [{
test: /\.css$/,
use: ['style-loader', 'css-loader','postcss-loader']
}
]
}
- 打包样式表中的图片和字体文件
- 运行 npm i url-loader file-loader -D 命令
- 在webpack.config.js的module->rules数组中,添加loader规则如下
module: {
rules: [{
test: /\.jpg|png|git|bmp|ttf|eot|svg|woff|woff2$/,
use: 'url-loader?limit=16940'
// ?之后的是loader的参数项
// limit用来指定图片的大小,单位是字节(byte),只有小于limit大小的图片才会杯转为base64图片,转成base64图片加载快点
}
]
}
- 打包处理js中高级语法 如class
- 安装babel转换器相关的包 npm i babel-loader @babel/core @babel/runtime -D
- 安装babel语法插件相关的包 npm i @babel/preset-env @babel/plugin-transform-runtime @babel/plugin-proposal-class-properties -D
- 项目根目录,创建babel.config.js 并初始化配置
module.exports={
presets:['@babel/preset-env'],
plugins:['@babel/plugin-transform-runtime','@babel/plugin-proposal-class-properties']
}
- 在webpack.config.js的module->rules数组中,添加loader规则
// exclude 为排除项,表示babel-loader不需要处理node_modules中的js文件
{
test:/.js$/,use:'babel-loader',exclude:/node_modules|jquery-3.5.1.min.js/
}
Vue 单文件组件
一个vue单文件组件中,包含template,script,style。
webpack中配置vue组件的加载器
- 运行npm i vue-loader vue-template-compiler -D
- 在webpack.config.js配置文件中,添加vue-loader的配置项如下
const VueLoaderPlugin = requir('vue-loader/lib/plugin')
module.exports = {
module:{
rules:[
//...其他规则
{test: /\.vue$/,loader:'vue-loader'}
]
},
plugins:[
// 其他插件
new VueLoaderPlugin()
]
}
webpack项目中使用vue
- 运行npm i vue -S 安装vue
- 在src-index.js入口文件中,通过import Vue from 'vue’来导入vue构造函数
- 创建vue的实例对象,并指定要控制的el区域
- 通过render函数渲染App跟组件
//1. 导入vue构造函数
import Vue from 'vue'
//2 导入App跟组件
import App from './components/App.vue'
const Vm = new Vue({
// 3. 指定vm实例要控制的页面区域
el:'#app'
// 通过render函数,吧指定的组件渲染导el区域中
render: h=>h(App)
})
webpack打包发布
通过package.json 文件配置打包命令:
// 在package.json 文件中配置webpack打包命令
// 该命令默认加载项目根目录中的webpack.config.js配置文件
"scripts":{
//用于打包的命令
"build":"webpack -p",
// 用于开发调试的命令
"dev":"webpack-dev-server --open --host --127.0.0.1 --port 3000"
}
运行 npm run build 进行打包,生成了dist文件
脚手架
Vue脚手架的基本用法
快速生成Vue项目基础架构 官网:https://cli.vuejs.org/zh/
使用步骤
- 安装3.x版本的脚手架
npm install -g @vue/cli
基于3.x版本的脚手架创建vue项目
// 命令行运行
//1. 基于交互式命令行的方式,创建新版vue项目
vue create my-project
//2. 基于图形化界面的方式,创建新版vue项目
vue ui
//3 基于2.x的旧模板,创建旧版vue项目
npm install -g @vue/cli-init
vue init webpack my-project
方法1:交互式命令方式
- vue create my-project
出现选中预设, 包含以前保存的,默认的和手动选择
- 手动选择后,空格选择需要选定的预设
3.输入n 使用v-router hash模式 (浏览器会出现#的符号),history没有
- 选择eslint模式(标准模式即可)
- 选择文件放置在哪(放单独文件中,以免package.json内容被弄乱)
进入项目目录,使用npm run serve启动项目
9.4.2脚手架自定义配置
- 通过packagejson配置项目
// 必须是符合规范的json语法
"vue":{
"devServer":{
"port":8888,
"open":true
}
}
注意:不推荐使用这种配置方式。因为package.json主要用来管理包的配置信息;为了方便维护,
推荐将vue脚手架相关的配置,d单独定义到vue.config.js配置文件中
- 通过单独的配置文件配置项目
- 在项目的根目录创建文件vue.config.js
- 在该文件中进行相关配置,从而覆盖默认配置
// vue.config.js
module.exports = {
devServer:{
port:8888
}
}
9.5 Element-ui 的基本使用
- 基于命令行方式手动安装
安装依赖包 npm i element-ui -S
main.js中导入Element-UI相关资源
// 导入组件库
import Element from 'element-ui'
// 导入组件相关样式
import 'element-ui/lib/them-chalk/index.css'
// 配置Vue插件
Vue.use(ElementUI)
- 基于图形化界面自动安装
- 运行 vue ui命令,打开图形化界面
- 通过vue项目管理器,进入项目配置面板
- 点击插件-添加插件
- 搜索vue-cli-plugin-elment 并安装
- 配置插件,实现按需导入,从而减少打包后项目体积