vue:核心功能—插件,组件,数据管理,生命周期
vue-router:路由机制—拆分,拆开,将文件划分大小
vuex:vue官方提供的数据共享机制,全局性管理数据
webpack:打包—js,css,图片,包的分隔,提供了很多开发功能
vue-loader:转换器
cli:脚手架,创建默认启动项目
vue-devtools:按照组件查找
前端渲染:性能更高,用户体验更好;所有的代码都需要用js写,所有的页面都需要被用户看到;
后端渲染:安全性高,SEO
结合:
vue-server-renderer:后端渲染的核心组件
nuxt.js:整合环境
element-UI
vue-element-admin
angular 09年,复杂,学习曲线长,一开始被大家拒绝
react 13年,用户体验良好
vue 14年,用户体验良好,尤雨溪,无锡人
引包
启动new Vue({el: 目的地,template:模板内容});
opations
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>vue的基本使用</title>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<!-- 数据绑定 -->
<!-- vue的模板语法 {{}} 双括号 -->
<h2>{{ name }}</h2> <!-- 绑定数据值 -->
<h3>{{ 1+1 }}</h3> <!-- 做运算 -->
<h4>{{ isTure }}</h4> <!-- 判断真假 -->
<h5>{{ str.split('').reverse().join('') }}</h5> <!-- 使用js中的方法 -->
<h1>{{ 1 > 2 ? '真' : '假' }}</h1> <!-- 使用三元表达式 -->
<h6>{{ {"name" : "张三"} }}</h6> <!-- 插入对象 -->
</div>
<script type="text/javascript">
// 2 创建实例化对象
var app = new Vue({
el: '#app', // el 挂载点,vue操作的对象
data: { // 数据属性
// 操作对象绑定的数据
// 既可以是一个对象,也可以是一个函数
name: '小陈',
hobby: '电子竞技', //data中数据发生改变,视图也会发生改变,简而言之,数据驱动视图
isTure: 1===1,
str: 'hello vue'
},
// 如果template中定义了内容 那么优先渲染 template 模板中的内容
// 如果没有定义内容,则加载的是#app中的模板
<!-- template: `{{ hobby }}` -->
template: ``
});
// 除了数据属性 vue 实例还暴露了一些有用的实例属性和方法
// 她们都有前缀$
console.log(app);
// 我们可以通过app.$数据名来获取vue实例中的数据
console.log(app.$data);
</script>
</body>
</html>
ng-xxx
开头vx-xxx
开头v-xxx
开头的就叫做指令v-text:元素的innerText属性,必须是双标签,跟{{}}效果是一样的,使用较少
v-html:元素的innerHtml
v-if :判断是否插入这个元素,相当于元素的销毁和创建
v-else-if
v-else
v-show:隐藏元素,如果元素确定要隐藏,会给元素的style加上display:none
,是基于css样式的切换
v-bind:给标签进行属性绑定(类似于:hover–给元素添加属性)【简写 :bind】
v-on:绑定事件
v-for:遍历
v-text:只能在双标签中使用,其实就是给元素的innerText赋值
v-html:其实就是给元素的innerHTML赋值
v-if:如果值为false,不在页面上渲染,会留下<!---->作为标记,但是可视化界面上面没有显示,如果值为true就将值显示在可视化界面上面
v-if,v-else-if都有相对应的值,v-else直接写
v-show是控制DOM元素显示与否,true显示,false隐藏
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>vue的基本使用</title>
<style type="text/css">
.obj {
width: 200px;
height: 200px;
border: 1px solid;
}
.obj2 {
width: 200px;
height: 200px;
border: 1px solid;
}
.active {
background-color: aqua;
}
table{
/* 去掉表格中的横向 内部边框线 */
border-collapse: collapse; /* 表格单元格间距样式 */
}
</style>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
</div>
<script type="text/javascript">
// 2 创建实例化对象
new Vue({
el: '#app',
data: function() {
return {
msg: 'v-text指令',
msg2: '斜体i标签',
isShow: false,
isBlue: false,
isRed: false,
text: 'chenhaha',
listData: [
{id: 1, name: '小陈', sex: '女'},
{id: 2, name: '小王', sex: '女'},
{id: 3, name: '小姜', sex: '女'},
{id: 4, name: '小唐', sex: '女'},
{id: 5, name: '小黎', sex: '女'},
{id: 6, name: '小肖', sex: '女'}
],
person: {
name: '筱辰',
hobby: '街舞,rap,吉他',
age: 20
}
}
},
template: `
// 通过text做数据的增加
雨天,写作业
晴天,出去耍,晒太阳
随机数大于0.5
随机数小于0.5
夏天
夏天
编号
姓名
性别
{{ item.id }}
{{ item.name }}
{{ item.sex }}
-
{{ key }} -------> {{ value }}
`,
methods: {
clickDiv(e) {
this.isBlue = !this.isBlue;
}
}
});
</script>
</body>
</html>
v-if 是 “真正”的条件渲染,因为他会确保在切换过程中条件块内的事件监听器和子组件适当的被销毁和重建
v-if也是惰性的:如果在初始渲染时条件为假,则什么也不做——知道条件第一次变为真时,才开始渲染条件块。
相比之下,v-show就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单的基于css进行切换。(导航栏)
一般来说,v-if有更高的切换开销,而v-show有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用v-show较好,如果在运行时条件很少改变,则使用v-if较好。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app">
<!-- 单项数据绑定 -->
<span>单项数据绑定:</span>
<input type="text" :value="mag"/>
<hr />
<!-- 双向数据绑定 只会体现在UI控件上面 只能应用在value属性上 -->
<span>双向数据绑定:</span>
<input type="text" v-model="msg"/>
<h1>{{ msg }}</h1>
<hr />
<!-- 实际上就是一个 语法糖,它是v-bind:value v-on:input的体现 -->
<span>双向数据实现原理:</span>
<input type="text" v-bind:value="mfg" v-on:input="valueChange"/>
<h1>{{ mfg }}</h1>
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
mag: "小猪佩奇",
msg: "好友记",
mfg: "肖申克的救赎"
}
},
methods: {
valueChange(e){
console.log(e.target.value);
this.mfg = e.target.value;
}
}
});
</script>
</body>
</html>
入口组件包含了:html,css,js
打油诗:声子 挂子 用子
创建:(类似于自定义全局组件,使用时直接在父组件中,通过局部组件的声明名调用即可)
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 局部入口组件的的声明
var App = {
data() {
return {
}
},
// 局部入口组件的内容
template:
`
我是局部入口组件
`
};
// 2 实例化对象
new Vue({
el: "#app",
data() {
return {
}
},
<!-- 挂载子组件 -->
components: {
App <!-- 类似于App:App -->
},
<!-- 父组件可以直接使用子组件 -->
template:
`
`
});
</script>
</body>
</html>
// 全局组件
// 第一个参数是组件的名字,第二个参数是组件的样式
Vue.component('V-button',{
template:
`
`
});
注意:在使用局部组件和全局组件时,不能单独使用,每个组件都是一个整体,在组件中使用全局组件和局部组件时,必须要写在组件的内部,它们是一个整体。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 全局组件
// 第一个参数是组件的名字,第二个参数是组件的样式
Vue.component('V-button',{
template:
`
`
});
// 声子
var Rightcentent = {
data() {
return {
}
},
template:
`
我是右边内容组件
`
};
<!-- 侧边栏组件 -->
var Leftcentent = {
data() {
return {
}
},
template:
`
我是左边菜单栏组件
`
};
<!-- 头部组件 -->
var Header = {
data() {
return {
}
},
template:
`
我是头部组件
`
};
// 局部入口组件的的声明
var App = {
data() {
return {
}
},
template: <!-- 用子 注意:在使用创建的子组件是是一个整体,不能分散开来,不然只能显示第一个子组件的值-->
`
`,
<!-- 挂子 -->
components: {
Header,
Leftcentent,
Rightcentent
}
};
// 2 实例化对象
new Vue({
el: "#app",
data() {
return {
}
},
<!-- 挂载子组件 -->
components: {
App <!-- 类似于App:App -->
},
<!-- 父组件可以直接使用子组件 -->
template:
`
`
});
</script>
</body>
</html>
1 先给父组件绑定自定义属性
2 在子组件中使用prop接收父组件传递的数据
3 只要使用props接收了数据之后,就可以在子组件中任意使用
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 声明全局组件 子组件
Vue.component('Child',{
template:
`
我是孩子
`,
<!-- 接收自定义属性 -->
props: ['childData']
});
<!-- 声明全局组件 父组件 -->
<!-- 1 先给父组件绑定自定义属性 -->
<!-- 2 在子组件中使用prop接收父组件传递的数据 -->
<!-- 3 只要使用props接收了数据之后,就可以在子组件中任意使用 -->
Vue.component('Parent',{
data() {
return {
msg: '我是父组件中的数据'
}
},
template:
`
我是父亲
`
});
// 声子
var App = {
template:
`
`
};
// 2 实例化对象
new Vue({
el: "#app",
data() {
return {
}
},
<!-- 挂载子组件 -->
components: {
App <!-- 类似于App:App -->
},
<!-- 父组件可以直接使用子组件 -->
template:
`
`
});
</script>
</body>
</html>
1.在父组件中绑定自定义事件
2.在子组件中触发原生的事件,在函数中使用$emit触发自定义函数
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 声明全局组件 子组件
Vue.component('Child',{
template:
`
我是孩子
`,
<!-- 接收自定义属性 -->
props: ['childData'],
methods: {
changeValue(val){
<!-- 自定义的时间一定通过thi.$emit()去触发 -->
<!-- 在函数中使用$emit(自定义的事件名,传递的消息) -->
this.$emit('childHeader',val);
}
}
});
<!-- 1.在父组件中绑定自定义事件 -->
<!-- 2.在子组件中触发原生的事件,在函数中使用$emit触发自定义函数 -->
Vue.component('Parent',{
data() {
return {
msg: '我是父组件中的数据'
}
},
template:
`
我是父亲
`,
methods: {
childHeader(val){
console.log(val);
}
}
});
// 声子
var App = {
template:
`
`
};
// 2 实例化对象
new Vue({
el: "#app",
data() {
return {
}
},
<!-- 挂载子组件 -->
components: {
App <!-- 类似于App:App -->
},
<!-- 父组件可以直接使用子组件 -->
template:
`
`
});
</script>
</body>
</html>
插槽:slot 插槽,作为承载分发内容的出口
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<style type="text/css">
.default {
display: inline-block;
line-height: 1;
white-space: nowrap;
cursor: pointer;
background: #fff;
border: 1px solid #dcdfe6;
color: #606266;
-webkit-appearance: none;
text-align: center;
box-sizing: border-box;
outline: none;
margin: 0;
transition: .1s;
font-weight: 500;
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
padding: 12px 20px;
font-size: 14px;
border-radius: 4px;
}
.primary {
color: #fff;
background-color: #409eff;
border-color: #409eff;
}
.success {
color: #fff;
background-color: green;
border-color: #409eff;
}
</style>
<!-- 1 引入vue包 -->
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 通过插槽的方式封装全局组件
Vue.component('Vbtn', {
template: `
`,
props: ['type']
});
<!-- 声子 -->
var Vcontent = {
template: `
我是内容组件
主要按钮
成功按钮
`
};
// 2 实例化对象
new Vue({
el: "#app",
data() {
return {
}
},
<!-- 挂子 -->
components: {
Vcontent <!-- 类似于App:App -->
},
<!-- 用子 -->
template: `
`
});
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="./node_modules/vue/dist/vue.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
Vue.component('myli',{
template:
`
预留的第一个空白
预留的第二个空白
`
})
var App = {
template:
`
我是第一个空白
我是第二个空白
`
}
<!-- 实例化vue -->
new Vue({
el: '#app',
components: {
App
},
template: ` `
});
</script>
</body>
</html>
过滤器的功能:就是为页面中的数据进行添油加醋的功能
过滤器的分类:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="./node_modules/vue/dist/vue.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 过滤器的功能:就是为页面中的数据进行添油加醋的功能
// 有两种:局部过滤器 全局过滤器
// 声明全局过滤器
Vue.filter('myReverse', function(value,arg) {
return arg + value.split('').reverse().join('');
});
var App = {
data() {
return {
price: 0,
msg: 'filter'
}
},
template:
`
{{ price | myCurrentcy }}
{{ msg | myReverse('I am going to study well you ') }}
`,
filters: {
<!-- 1 声明局部过滤器 -->
myCurrentcy: function(value) {
return "¥" + value;
}
}
}
<!-- 实例化vue -->
new Vue({
el: '#app',
components: {
App
},
template: ` `
});
</script>
</body>
</html>
watch监听的是单个属性。
基本的数据类型,简单监视。
复杂的数据类型深度监视。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="./node_modules/vue/dist/vue.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="msg">
<h2>{{ msg }}</h2>
<button type="button" @click="stus[0].name = 'rose'">获取用户名</button>
<h4>{{ stus[0].name }}</h4>
</div>
<script type="text/javascript">
new Vue({
el: '#app',
data() {
return {
msg: '',
stus: [{name: 'jack'}]
}
},
watch: {
//简单监视
// 字符串
msg: function(newV, oldV) {
console.log(newV, oldV);
},
//深度监视
stus:{
deep: true,
handler:function(newV, oldV) {
console.log(newV, oldV);
console.log(newV[0].name);
}
}
}
})
</script>
</body>
</html>
利用computed计算属性写网页版音乐播放器。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<style type="text/css">
*{
padding: 0;
margin: 0;
}
ul{
list-style: none;
}
ul li {
margin: 20px 20px;
padding: 20px 20px;
}
.active{
background-color: aquamarine;
}
</style>
<script src="./node_modules/vue/dist/vue.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<audio :src='getCurrentSongSrc' autoplay="autoplay" controls="controls"></audio>
<ul>
<li v-for="(item,index) in musicData" @click="clickHander(index)" :class="{active:currentIndex == index}">
<h2>{{ item.id }} - 歌名:{{ item.name }}h2>
<p>歌曲来源:{{ item.sonSrc }}</p>
</li>
</ul>
</div>
<script type="text/javascript">
var musicData = [
{
id: 1,
name: '世界美好与你环环相扣',
author: '柏松',
sonSrc: 'music/世界美好与你环环相扣.mp3'
},
{
id: 2,
name: '昨天的你现在的未来',
author: '易烊千玺',
sonSrc: 'music/昨天的你现在的未来.mp3'
},
{
id: 3,
name: '精彩才刚刚开始',
author: '易烊千玺',
sonSrc: 'music/精彩才刚刚开始.mp3'
}
];
new Vue({
el: '#app',
data() {
return {
musicData:musicData,
currentIndex:0
}
},
computed:{
// 计算属性默认只有getter
// setter也可以
// 使用getter
// getCurrentSongSrc:function(){
// return this.musicData[this.currentIndex].sonSrc
// }
// 使用setter
getCurrentSongSrc:{
set: function(newV){
console.log(newV);
this.currentIndex = newV;
},
get:function(){
return this.musicData[this.currentIndex].sonSrc
}
}
},
methods:{
clickHander(index){
// 使用getter
// 直接修改数据的属性
// this.currentIndex = index;
// 使用setter
console.log(this.getCurrentSongSrc);
this.getCurrentSongSrc = index;
}
}
})
</script>
</body>
</html>
beforeCreate
created
beforeMount
mounted
beforeUpdate
updated
在更新DOM之后调用该钩子,应用:可以获取原始的DOM
beforeDeatory
destroyed
activated
deactivated
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="./node_modules/vue/dist/vue.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<App></App>
</div>
<script type="text/javascript">
Vue.component('Test', {
data() {
return {
msg: 'lorry'
}
},
template: `
{{ msg }}
`,
methods: {
changerHanlder() {
this.msg = this.msg + 'hello';
}
},
beforeCreate: function() {
<!-- 组件创建之前 -->
console.log(this.msg); <!-- 打印输出undefined -->
},
created: function() {
<!-- 组件创建之后 -->
console.log(this.msg); <!-- 打印输出lorry -->
<!-- 使用该组件,就会调用created方法 -->
<!-- 在created这个方法中可以操作后端的数据,数据驱动视图 -->
<!-- 应用:发起ajax请求 -->
},
beforeMount: function() {
<!-- 挂载数据之前 --> <!-- 打印输出<div id="app"><app></app></div> -->
console.log(document.getElementById('app'));
},
mounted: function() {
<!-- 挂载数据到DOM之后 Vue作用之后的DOM-->
<!-- 打印输出<div id="app"><div class="app"><div><h2>lorry</h2></div></div></div> -->
console.log(document.getElementById('app'));
},
beforeUpdate: function() {
<!-- 在更新Dom之前使用改方法 -->
<!-- 打印输出 <div class="app"><div><h2>lorry</h2> <button>改变</button></div></div> -->
console.log(document.getElementById('app').innerHTML);
},
updated: function() {
<!-- 在更新DOM之后使用该方法 -->
<!-- 打印输出 <div class="app"><div><h2>lorryhello</h2> <button>改变</button></div></div> -->
console.log(document.getElementById('app').innerHTML);
},
beforeDeatory: function() {
<!-- 销毁数据之前 -->
console.log('beforeDeatory'); <!-- Test组件中内容的显示隐藏的时候,打印输出beforeDeatory -->
},
destroyed: function() {
<!-- 销毁数据之后 -->
console.log('destroyed'); <!-- Test组件中内容的显示显示的时候,打印输出destroyed -->
},
activated: function() {
console.log('组件被激活了');
},
deactivated: function() {
console.log('组件被停用了');
},
});
var App = {
data() {
return {
isShow: true
}
},
template: `
`
};
new Vue({
el: '#app',
data() {
return {
}
},
components: {
App
}
})
</script>
</body>
</html>
在组件的切换过程中将所有的状态保存在内存中,重复渲染DOM(缓存)
keep-alive保存加载过的数据,使用时直接调用,不用再次加载,节省项目运行时间,提高用户体验。
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script src="./node_modules/vue-router/dist/vue-router.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
var Timeline = {
template:
`
首页
`,
created() {
console.log('首页组件创建了');
},
mounted() {
console.log('首页组件DOM加载了');
},
destroyed() {
console.log('首页组件销毁了');
}
};
var Pins = {
template:
`
沸点
`,
methods: {
clickHandle(e) {
e.target.style.color = 'red';
}
},
created() {
console.log('沸点组件创建了');
},
mounted() {
console.log('沸点组件DOM加载了');
},
destroyed() {
console.log('沸点组件销毁了');
}
};
<!-- // 创建路由对象 -->
var router = new VueRouter({
<!-- mode: 'history', 哈希模式,页面跳转时路由不会出现# -->
routes:[
{
path: '/timeline',
component: Timeline
},
{
path: '/pins',
component: Pins
}
]
});
<!-- // 实例化app组件 -->
var App = {
template:
`
首页
沸点
`
}
<!-- // 实例化对象 -->
new Vue({
el: '#app',
router,
template: ` `,
<!-- 挂载组件 -->
components: {
App
}
})
</script>
</body>
</html>
vue组件之间通信可分为:
父组件向子组件传递数据是通过props传递的,子组件传递数据给父组件是通过$emit触发事件来做到的。
解决父子组件层数较少的情况
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.js"></script>
<script type="text/javascript">
/*
在下面的例子中,有父组件App和子组件Child。
1).父组件传递了message数据给子组件,并且通过v-on绑定了一个getChildData事件来监听子组件的触发事件;
2).子组件通过props得到相关的message数据,最后通过this.$emit触发了getChildData事件。
*/
Vue.component('Child',{
data(){
return {
aaa:this.message
}
},
template:`
`,
props:['message'],
methods:{
passData(val){
// $emit(自定义事件名,传递的值)
this.$emit('getChildData',val);
}
}
});
var App = {
data(){
return {
msg:'我是父组件的内容'
}
},
methods:{
getChildData(val){
console.log(`我是子组件传进来的${val}`);
}
},
template:`
这是一个父组件
`
}
new Vue({
el:"#app",
data(){
return {
}
},
components:{
App
},
template:` `
});
</script>
</body>
</html>
a t t r s 是 attrs是 attrs是pops的集合
解决多层组件之间的嵌套和传值方法
绑定事件,传值,然后通过事件来接收传递的值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script type="text/javascript">
/*
$attrs和$listeners
第一种方式处理父子组件之间的数据传输有一个问题: 如果父组件A下面有子组件B, 组件B下面有组件C, 这时如果组件A想传递数据给组件C怎么办呢?
如果采用第一种方法, 我们必须让组件A通过prop传递消息给组件B, 组件B在通过prop传递消息给组件C; 要是组件A和组件C之间有更多的组件, 那采用这种方式就很复杂了。 Vue 2.4 开始提供了$attrs和$listeners来解决这个问题, 能够让组件A之间传递消息给组件C。
*/
Vue.component('C', {
data() {
return {
}
},
template: `
{{$attrs.messagec}}
`,
methods: {
cClickHandler(){
alert(1);
this.$emit('getCData','我是c的数据')
}
}
});
Vue.component('B', {
data() {
return {
}
},
template: `
`,
methods: {
}
});
Vue.component('A', {
data() {
return {
}
},
// props:['message'],
template: `
`,
methods: {
}
});
var App = {
data() {
return {
msg: '我是父组件的内容',
messagec:'hello c'
}
},
methods: {
},
template: ``,
methods:{
// 执行c组件的触发的函数
getCData(val){
console.log(val);
}
}
};
new Vue({
el: "#app",
data() {
return {
}
},
components: {
App
},
template: ` `
});
</script>
</body>
</html>
$on
绑定自定义事件,$emit
触发自定义事件
$on
和$emit
绑定同一个实例化对象
解决兄弟组件之间的传值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script type="text/javascript">
/*
上面两种方式处理的都是父子组件之间的数据传递,而如果两个组件不是父子关系呢?这种情况下可以使用中央事件总线的方式。新建一个Vue事件bus对象,然后通过bus.$emit触发事件,bus.$on监听触发的事件。
*/
// 中央事件总线
var bus = new Vue();
Vue.component('brother2', {
data() {
return {
msg:"hello brother1"
}
},
template: `
我是老大
`,
methods: {
passData(val){
// //触发全局事件globalEvent
bus.$emit('globalEvent',val)
}
}
});
Vue.component('brother1', {
data() {
return {
msg:"hello brother1",
brother2Msg:''
}
},
template: `
我是老二
老大传递过来的数据:{{brother2Msg}}
`,
mounted(){
// 绑定全局事件globalEvent事件,
bus.$on('globalEvent',(val)=>{
bus.brother2Msg = val;
})
}
});
var App = {
data() {
return {
msg: '我是父组件的内容',
messagec:'hello c'
}
},
methods: {
},
template: `
`,
methods:{
// 执行c组件的触发的函数
getCData(val){
console.log(val);
}
}
}
new Vue({
el: "#app",
data() {
return {
}
},
components: {
App
},
template: ` `
});
</script>
</body>
</html>
父组件中通过provide来提供变量,然后在子组件中通过inject来注入变量。不论子组件有多深,只要调用了inject那么就可以注入provider中的数据。而不是局限于只能从当前父组件的prop属性来获取数据,只要在父组件的生命周期内,子组件都可以调用。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script type="text/javascript">
Vue.component('Child',{
data(){
return {
msg:''
}
},
template:`
我是孩子{{msg}}
`,
inject:['for'],
created(){
// 拿到传递过来的值
this.msg = this.for;
}
});
Vue.component('Parent',{
template:`
我是父亲
`
});
var App = {
data(){
return {
}
},
provide:{
for:'他爹'
},
template:`
我是入口组件
`
}
new Vue({
el:"#app",
template:` `,
data(){
return {
}
},
components:{
App
}
});
</script>
</body>
</html>
挂载父组件,在子组件中通过props去接收
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script type="text/javascript">
Vue.component('Child', {
props: {
value: String, //v-model会自动传递一个字段为value的prop属性
},
data() {
return {
// 将value 的值赋值给 mymessage
mymessage: this.value
}
},
methods: {
changeValue() {
console.log(this.mymessage);
this.$parent.message = this.mymessage; //通过如此调用可以改变父组件的值
console.log(this.$parent);
}
},
template: `
`
})
Vue.component('Parent',{
// 点击按钮,将mymessage的值传递给子组件
template:`
我是父亲组件{{message}}
`,
methods:{
changeChildValue(){
this.$children[0].mymessage = 'hello';
}
},
data(){
return {
message:'hello'
}
}
})
var App = {
data(){
return {
}
},
template:`
我是入口组件
`
}
var vm = new Vue({
el:'#app',
components:{
App
},
template:`
`
})
console.log(vm);
</script>
</body>
</html>
Vuex原理
Vuex实现了一个单向数据流,在全局拥有一个State存放数据,当组件要更改State中的数据时,必须通过Mutation进行,Mutation同时提供了订阅者模式供外部插件调用获取State数据的更新。而当所有异步操作(常见于调用后端接口异步获取更新数据)或批量的同步操作需要走Action,但Action也是无法直接修改State的,还是需要通过Mutation来修改State的数据。最后,根据State的变化,渲染到视图上。
各模块之间的工作流程
$store.dispatch('action 名称', data1)
来触发。然后由commit()来触发mutation的调用 , 间接更新 state。负责处理Vue Components接收到的所有交互行为。包含同步/异步操作,支持多个同名方法,按照注册的顺序依次触发。向后台API请求的操作就在这个模块中进行,包括触发其他action以及提交mutation的操作。该模块提供了Promise的封装,以支持action的链式触发。commit('mutation 名称')
来触发。是Vuex修改state的唯一推荐方法。该方法只能进行同步操作,且方法名只能全局唯一。操作之中会有一些hook暴露出来,以进行state的监控等。Vuex与localStorage
vuex 是 vue 的状态管理器,存储的数据是响应式的。但是并不会保存起来,刷新之后就回到了初始状态, **具体做法应该在vuex里数据改变的时候把数据拷贝一份保存到localStorage里面,刷新之后,如果 localStorage里有保存的数据,取出来再替换store里的state。**
let defaultCity = "上海"
try { // 用户关闭了本地存储功能,此时在外层加个try...catch
if (!defaultCity){
defaultCity = JSON.parse(window.localStorage.getItem('defaultCity'))
}
}catch(e){}
export default new Vuex.Store({
state: {
city: defaultCity
},
mutations: {
changeCity(state, city) {
state.city = city
try {
window.localStorage.setItem('defaultCity', JSON.stringify(state.city));
// 数据改变的时候把数据拷贝一份保存到localStorage里面
} catch (e) {}
}
}
})
复制代码
这里需要注意的是:由于vuex里,我们保存的状态,都是数组,而localStorage只支持字符串,所以需要用JSON转换:
JSON.stringify(state.subscribeList); // array -> string
JSON.parse(window.localStorage.getItem("subscribeList")); // string -> array
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="./node_modules/vue/dist/vue.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 组件的挂载
Vue.component('SubCom', {
template:
`
`
});
var App = {
template:
`
b
`,
created() {
<!-- 获取所有的加上有ref属性的集合 -->
console.log(this.$refs.btn);
},
beforeMount:function() {
<!-- 获取所有的加上有ref属性的集合 -->
console.log(this.$refs.btn);
},
mounted() {
<!-- 如果给标签蚌寺那个ref = 'xxx' 属性,使用this.$refs.xxx获取原生的js对象 -->
<!-- ref属性值不能重名 -->
console.log(this.$refs.btn);
console.log(this.$refs.btn2);
<!-- 如果是给自定义组件绑定ref属性,那么this.$refs.abc获取的是当前的组件对象 -->
console.log(this.$refs.abc);
}
};
new Vue({
el: '#app',
data() {
return {
}
},
template: ` `,
components: {
App
}
});
</script>
</body>
</html>
使用focus()方法,获取焦点事件
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="./node_modules/vue/dist/vue.min.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
var App = {
data() {
return {
isShow: false
}
},
template:
`
`,
mounted() {
this.isShow = true;
<!-- 能获取到input框,但是不能使用focus()方法 -->
console.log(this.$refs.input);
<!-- 在Dom更新 -->
<!-- $nextTick()方法,在DOM更新循环之后执行回调函数,再修改数据之后可以使用此方法,在回调函数中获取到更新之后的数据 -->
<!-- this.$ref.input.focus(); -->
this.$nextTick(function() {
console.log(this);
<!-- 窗体加载的时候input框默认触发焦点事件 -->
this.$refs.input.focus();
});
}
};
new Vue({
el: '#app',
data() {
return {
}
},
template: ` `,
components: {
App
}
});
</script>
</body>
</html>
传统开发方式url改变后,立刻发生请求响应整个页面,有可能资源过多,传统开发会让页面出现白屏
前端路由的原理
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
</head>
<body>
<a href="#/login">登录</a>
<a href="#/register">注册</a>
<div id="app"></div>
<script type="text/javascript">
var oDiv = document.getElementById('app');
// onhashchange方法,哈希值改变后调用的方法
// a标签中href属性的值就是哈希值
window.onhashchange = function(){
// 访问到用户点击的哈希值
console.log(location.hash);
// 根据哈希值来做相对应的处理
switch (location.hash){
case '#/login':
oDiv.innerHTML = '我是登录页面
'
break;
case '#/register':
oDiv.innerHTML = '我是注册页面
'
break;
default:
break;
}
}
</script>
</body>
</html>
SPA(Single Page Application) 单页面应用
下载packag.json配置文件
npm init --yes
下载vue包
npm install vue --save
下载vue-router包
npm install vue-router -S
使用:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 1引入vue模块-->
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 2 引入vue-router模块 -->
<!-- 引入vue-router模块后 会抛出两个全局组件 router-link 和 router-view -->
<!-- router-link 相当于a标签 ,router-link中的to属性相当于a标签的href属性 -->
<!-- router-view 路由匹配组件的出口 -->
<script src="./node_modules/vue-router/dist/vue-router.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 创建使用vue-router
// 3 让Vue使用VueRouter创建
Vue.use(VueRouter);
var Login = {
template: `
我是登陆页面
`
};
var Register = {
template: `
我是注册页面
`
};
<!-- // 4 创建router对象 -->
var router = new VueRouter({
<!-- //5 配置路由对象 -->
routes: [
<!-- // 路由匹配的规则 -->
<!-- 当路径为login时,自动匹配Login组件,然后加载组件中的内容 -->
{
path: "/login",
component: Login
},
{
path: "/register",
component: Register
},
]
});
<!-- // 声明组件 -->
var App = {
template: `
登录页面
注册页面
`
}
new Vue({
el: '#app',
data() {
return {
}
},
components: {
App
},
<!-- 将 router 路由交给Vue实例化对象管理-->
router,
template: ` `
})
</script>
</body>
</html>
绑定to属性,匹配路由对象(通过定义的name来使用)
routes中的path属于动态路由参数,以冒号开头
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 1引入vue模块-->
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 2 引入vue-router模块 -->
<!-- 引入vue-router模块后 会抛出两个全局组件 router-link 和 router-view -->
<!-- router-link 相当于a标签 ,router-link中的to属性相当于a标签的href属性 -->
<!-- router-view 路由匹配组件的出口 -->
<script src="./node_modules/vue-router/dist/vue-router.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 创建使用vue-router
// 3 让Vue使用VueRouter创建
Vue.use(VueRouter);
var Login = {
template: `
我是登陆页面
`
};
var Register = {
template: `
我是注册页面
`
};
<!-- // 4 创建router对象 -->
var router = new VueRouter({
<!-- //5 配置路由对象 -->
routes: [
<!-- // 路由匹配的规则 -->
<!-- 当路径为login时,自动匹配Login组件,然后加载组件中的内容 -->
{
path: "/login",
name: "login", <!-- 给当前路由命名 -->
component: Login
},
{
path: "/register",
name: "register",
component: Register
},
]
});
<!-- // 声明组件 -->
var App = {
template: `
登录页面
登录页面
`
}
new Vue({
el: '#app',
data() {
return {
}
},
components: {
App
},
<!-- 将 router 路由交给Vue实例化对象管理-->
router,
template: ` `
})
</script>
</body>
</html>
路由范式(规则):
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 1引入vue模块-->
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 2 引入vue-router模块 -->
<!-- 引入vue-router模块后 会抛出两个全局组件 router-link 和 router-view -->
<!-- router-link 相当于a标签 ,router-link中的to属性相当于a标签的href属性 -->
<!-- router-view 路由匹配组件的出口 -->
<script src="./node_modules/vue-router/dist/vue-router.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 创建使用vue-router
// 3 让Vue使用VueRouter创建
Vue.use(VueRouter);
var userParams = {
template: `
我是用户1
`,
created() {
<!--引入vue-router时就会抛出两个对象 -->
<!-- 这两个对象就挂载到Vue实例化对象 -->
console.log(this.$router);
console.log(this.$route);
<!-- 获取用户点击的id -->
<!-- 注意通过 :id传递了id参数参能获取到id的值 -->
console.log(this.$route.params.id);
}
};
var userQuery = {
template: `
我是用户2
`
};
<!-- // 4 创建router对象 -->
var router = new VueRouter({
<!-- //5 配置路由对象 -->
routes: [
<!-- // 路由匹配的规则 -->
<!-- 当路径为login时,自动匹配Login组件,然后加载组件中的内容 -->
{
path: "/user/:id",
<!-- params动态参数 -->
name: "userP", <!-- 给当前路由命名 -->
component: userParams
},
{
path: "/user",
<!-- query 查询 -->
name: "userQ",
component: userQuery
},
]
});
<!-- // 声明组件 -->
var App = {
template: `
用户1
用户2
`
}
new Vue({
el: '#app',
data() {
return {
}
},
components: {
App
},
<!-- 将 router 路由交给Vue实例化对象管理-->
router,
template: ` `
})
</script>
</body>
</html>
菜单栏的动态切换,标题栏一样,通过小组件来实现页面的动态切换
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 1引入vue模块-->
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 2 引入vue-router模块 -->
<!-- 引入vue-router模块后 会抛出两个全局组件 router-link 和 router-view -->
<!-- router-link 相当于a标签 ,router-link中的to属性相当于a标签的href属性 -->
<!-- router-view 路由匹配组件的出口 -->
<script src="./node_modules/vue-router/dist/vue-router.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 创建使用vue-router
// 3 让Vue使用VueRouter创建
Vue.use(VueRouter);
<!-- 内层小组件 -->
var Song = {
template:
`
歌曲列表
`
};
var Movie = {
template:
`
电影列表
`
};
<!-- // 外层大组件 -->
<!-- 注意:每一个组件模板都是一个大的整体,需要在一个盒子里面 -->
var Home = {
template: `
首页
歌曲
电影
`
};
<!-- // 4 创建router对象 -->
var router = new VueRouter({
<!-- //5 配置路由对象 -->
routes: [
<!-- // 路由匹配的规则 -->
<!-- 当路径为login时,自动匹配Login组件,然后加载组件中的内容 -->
{
path: "/home",
<!-- params动态参数 -->
name: "home", <!-- 给当前路由命名 -->
component: Home,
<!-- 匹配多层目录下面的子目录 -->
children: [
{
path: "song",
<!-- params动态参数 -->
component: Song
},
{
path: "movie",
<!-- params动态参数 -->
component: Movie
},
]
}
]
});
<!-- // 声明组件 -->
var App = {
template: `
首页
`
}
new Vue({
el: '#app',
data() {
return {
}
},
components: {
App
},
<!-- 将 router 路由交给Vue实例化对象管理-->
router,
template: ` `
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script src="./node_modules/vue-router/dist/vue-router.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// 当前使用路由参数,列入/timeline/fronted导航到/timeline/backed,原来的组件实例会被复用,
// 因为两个路由都渲染同个组件,比起销毁在创建,复用则显得更高效,不过这也意味着组件的生命周期
// 不会再被调用
var ComDesc = {
data() {
return {
msg: ''
}
},
template:
`
我是{{ msg }}
`,
created() {
<!-- created方法只会走一次 -->
<!-- created可以发Ajax请求 -->
this.msg = '前端';
},
<!-- watch在当前组件内部监听路由信息的变化 -->
watch: {
'$route'(to,from) {
console.log(to); <!-- to就是一个routes对象 -->
console.log(from);
<!-- 发送ajax请求,获取到对应的参数 -->
this.msg = to.params.id;
}
}
};
var Timeline = {
template:
`
前端
后端
`
};
var Pins = {
template:
`
沸点
`
};
<!-- // 创建路由对象 -->
var router = new VueRouter({
<!-- mode: 'history', 哈希模式,页面跳转时路由不会出现# -->
routes:[
{
path: '/timeline',
component: Timeline,
children: [
{
name: 'comDesc',
<!-- 动态路由的参数 以:开头 -->
path: '/timeline/:id',
component: ComDesc
}
]
},
{
path: '/pins',
component: Pins
}
]
});
<!-- // 实例化app组件 -->
var App = {
template:
`
首页
沸点
`
}
<!-- // 实例化对象 -->
new Vue({
el: '#app',
router,
template: ` `,
<!-- 挂载组件 -->
components: {
App
}
})
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<script src="./node_modules/vue-router/dist/vue-router.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<router-link to = '/home'>首页</router-link>
<router-link to = '/blog'>我的博客</router-link>
<router-link to = '/login'>登录</router-link>
<a href="javascript:void(0)">退出</a>
<!-- 每个路由组件都渲染到router-view里面了 -->
<router-view></router-view>
</div>
<script type="text/javascript">
Vue.use(VueRouter);
var Home = {
template:
`
首页
`
};
var Blog = {
template:
`
我的博客
`
};
var Login = {
data() {
return {
name: '',
pwd: ''
}
},
template:
`
`,
methods: {
loginHandle() {
<!-- 登录 -->
<!-- 将用户名 密码保存下来 -->
localStorage.setItem('user', {name:this.name,pwd:this.pwd});
<!-- 跳转到博客页面 -->
<!-- 编程式导航 -->
this.$router.push({
name: 'blog'
})
}
}
};
<!-- // 创建路由对象 -->
var router = new VueRouter({
<!-- mode: 'history', 哈希模式,页面跳转时路由不会出现# -->
routes:[
{
path: '/',
redirect: '/home'
},
{
path: '/home',
component: Home
},
{
path: '/blog',
name: 'blog',
component: Blog,
<!-- meta给未来的路由做权限控制 -->
meta: {
<!-- 证明用户访问该组件的时候需要登录 -->
auth: true
}
},
{
path: '/login',
component: Login
}
]
});
<!-- 全局路由匹配 -->
<!-- beforeEach会监测路由 -->
router.beforeEach((to, from, next) => {
console.log(to);
console.log(from);
if(to.meta.auth) { <!-- true -->
if (localStorage.getItem('user')) {
<!-- 如果localStorage有值则证明用户登录完成了 -->
next();
}else{
<!-- 用户需要登录 -->
next({
path: '/login'
});
}
} else {
<!-- false 直接放行 -->
<!-- 如果不调用 next() 方法会卡主页面-->
next();
}
});
<!-- // 实例化对象 -->
new Vue({
el: '#app',
router, <!-- 挂载路由 -->
})
</script>
</body>
</html>
Axios是一个基于promise的HTTP库,可以在浏览器和node.js中使用。
作用:
XMLHttpRequests
http
请求Promise
APIXSRF
攻击参考文档链接:https://www.kancloud.cn/yunye/axios/234845
安装
使用npm:
npm install axios
使用bower:
bower install axios
使用cdn:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 引包vue -->
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 引包axios -->
<script src="./node_modules/axios/dist/axios.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// console.log(axios);
var App = {
template:
`
`,
methods: {
sendAjax(){
this.$axios.get('http://127.0.0.1:8888/')
.then(res => {
<!-- 拿到statusText: "OK" -->
console.log(res.data.msg); <!-- 打印输出ok -->
})
.catch(err => {
console.log(err);
})
}
}
};
Vue.prototype.$axios = axios;
new Vue({
el: '#app',
data() {
return {
}
},
template: ` `,
components: {
App
}
});
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<!-- 引包vue -->
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 引包axios -->
<script src="./node_modules/axios/dist/axios.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// console.log(axios);
var App = {
data() {
return {
res1: '',
res2: ''
}
},
template: `
响应1: {{ res1 }},
响应2: {{ res2 }},
`,
methods: {
sendAjax() {
<!-- 请求1 get: /-->
<!-- 请求2 post :/add -->
<!-- 配置 -->
this.$axios.defaults.baseURL = `http://127.0.0.1:8888/`;
<!-- 发请求 -->
var r1 = this.$axios.get('');
var r2 = this.$axios.post('add','a = 1');
this.$axios.all([r1, r2])
.then(this.$axios.spread((res1,res2) => {
<!-- 请求全部成功 -->
this.res1 = res1.data;
this.res2 = res2.data;
}))
.catch(err => {
<!-- 有一个失败就失败了 -->
console.log(err);
})
}
}
};
Vue.prototype.$axios = axios;
new Vue({
el: '#app',
data() {
return {
}
},
template: ` `,
components: {
App
}
});
</script>
</body>
</html>
这些是创建请求时可以用的配置选项。只有url
是必需的。如果没有指定method
,请求将使用替代get
方法。
{
// `url` 是用于请求的服务器 URL
url: '/user',
// `method` 是创建请求时使用的方法
method: 'get', // 默认是 get
// `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
baseURL: 'https://some-domain.com/api/',
// `transformRequest` 允许在向服务器发送前,修改请求数据
// 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
// 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
transformRequest: [function (data) {
// 对 data 进行任意转换处理
return data;
}],
// `transformResponse` 在传递给 then/catch 前,允许修改响应数据
transformResponse: [function (data) {
// 对 data 进行任意转换处理
return data;
}],
// `headers` 是即将被发送的自定义请求头
headers: {'X-Requested-With': 'XMLHttpRequest'},
// `params` 是即将与请求一起发送的 URL 参数
// 必须是一个无格式对象(plain object)或 URLSearchParams 对象
params: {
ID: 12345
},
// `paramsSerializer` 是一个负责 `params` 序列化的函数
// (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
paramsSerializer: function(params) {
return Qs.stringify(params, {arrayFormat: 'brackets'})
},
// `data` 是作为请求主体被发送的数据
// 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
// 在没有设置 `transformRequest` 时,必须是以下类型之一:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - 浏览器专属:FormData, File, Blob
// - Node 专属: Stream
data: {
firstName: 'Fred'
},
// `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
// 如果请求话费了超过 `timeout` 的时间,请求将被中断
timeout: 1000,
// `withCredentials` 表示跨域请求时是否需要使用凭证
withCredentials: false, // 默认的
// `adapter` 允许自定义处理请求,以使测试更轻松
// 返回一个 promise 并应用一个有效的响应 (查阅 [response docs](#response-api)).
adapter: function (config) {
/* ... */
},
// `auth` 表示应该使用 HTTP 基础验证,并提供凭据
// 这将设置一个 `Authorization` 头,覆写掉现有的任意使用 `headers` 设置的自定义 `Authorization`头
auth: {
username: 'janedoe',
password: 's00pers3cret'
},
// `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
responseType: 'json', // 默认的
// `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称
xsrfCookieName: 'XSRF-TOKEN', // default
// `xsrfHeaderName` 是承载 xsrf token 的值的 HTTP 头的名称
xsrfHeaderName: 'X-XSRF-TOKEN', // 默认的
// `onUploadProgress` 允许为上传处理进度事件
onUploadProgress: function (progressEvent) {
// 对原生进度事件的处理
},
// `onDownloadProgress` 允许为下载处理进度事件
onDownloadProgress: function (progressEvent) {
// 对原生进度事件的处理
},
// `maxContentLength` 定义允许的响应内容的最大尺寸
maxContentLength: 2000,
// `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject promise 。如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否则,promise 将被 rejecte
validateStatus: function (status) {
return status >= 200 && status < 300; // 默认的
},
// `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目
// 如果设置为0,将不会 follow 任何重定向
maxRedirects: 5, // 默认的
// `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理。允许像这样配置选项:
// `keepAlive` 默认没有启用
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),
// 'proxy' 定义代理服务器的主机名称和端口
// `auth` 表示 HTTP 基础验证应当用于连接代理,并提供凭据
// 这将会设置一个 `Proxy-Authorization` 头,覆写掉已有的通过使用 `header` 设置的自定义 `Proxy-Authorization` 头。
proxy: {
host: '127.0.0.1',
port: 9000,
auth: : {
username: 'mikeymike',
password: 'rapunz3l'
}
},
// `cancelToken` 指定用于取消请求的 cancel token
// (查看后面的 Cancellation 这节了解更多)
cancelToken: new CancelToken(function (cancel) {
})
}
在请求或响应被then
或catch
处理前拦截它们。
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
如果你想在以后可移除拦截器,可以这样:
var myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
可以为自定义axios实例添加拦截器
var instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});
axios.get('/user/12345')
.catch(function (error) {
if (error.response) {
// 请求已发出,但服务器响应的状态码不在 2xx 范围内
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
}
console.log(error.config);
});
可以使用validateStatus
配置选项定义一个自定义HTTP状态码的错误范围。
axios.get('/user/12345', {
validateStatus: function (status) {
return status < 500; // 状态码在大于或等于500时才会 reject
}
})
使用取消令牌取消请求
Axios的取消令牌API基于cancelable promises提议,它还处于第一阶段。
可以使用CancelToken.source
工厂方法创建cancel token,像这样:
var CancelToken = axios.CancelToken;
var source = CancelToken.source();
axios.get('/user/12345', {
cancelToken: source.token
}).catch(function(thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// 处理错误
}
});
// 取消请求(message 参数是可选的)
source.cancel('Operation canceled by the user.');
还可以通过传递一个executor函数到CancelToken
的构造函数来创建取消令牌:
var CancelToken = axios.CancelToken;
var cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
// executor 函数接收一个 cancel 函数作为参数
cancel = c;
})
});
// 取消请求
cancel();
注意:可以使用同一个cancel token取消多个请求
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title></title>
<style type="text/css">
.spinner {
margin: 100px auto;
width: 50px;
height: 60px;
text-align: center;
font-size: 10px;
}
.spinner>div {
background-color: #67CF22;
height: 100%;
width: 6px;
display: inline-block;
-webkit-animation: stretchdelay 1.2s infinite ease-in-out;
animation: stretchdelay 1.2s infinite ease-in-out;
}
.spinner .rect2 {
-webkit-animation-delay: -1.1s;
animation-delay: -1.1s;
}
.spinner .rect3 {
-webkit-animation-delay: -1.0s;
animation-delay: -1.0s;
}
.spinner .rect4 {
-webkit-animation-delay: -0.9s;
animation-delay: -0.9s;
}
.spinner .rect5 {
-webkit-animation-delay: -0.8s;
animation-delay: -0.8s;
}
@-webkit-keyframes stretchdelay {
0%,
40%,
100% {
-webkit-transform: scaleY(0.4)
}
20% {
-webkit-transform: scaleY(1.0)
}
}
@keyframes stretchdelay {
0%,
40%,
100% {
transform: scaleY(0.4);
-webkit-transform: scaleY(0.4);
}
20% {
transform: scaleY(1.0);
-webkit-transform: scaleY(1.0);
}
}
</style>
<!-- 引包vue -->
<script src="./node_modules/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script>
<!-- 引包axios -->
<script src="./node_modules/axios/dist/axios.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
// console.log(axios);
var App = {
data() {
return {
isShow: false
}
},
template: `
`,
methods: {
sendAjax() {
<!-- 模拟类似cookie的机制 -->
<!-- 添加请求拦截器 -->
this.$axios.interceptors.request.use((config) => {
console.log(config);
var token = localStorage.setItem('token');
if (token) {
config.headers['token'] = token;
}
this.isShow = true;
return config;
}, function(err) {
return Promise.reject(err);
});
<!-- // 添加响应拦截器 -->
this.$axios.interceptors.response.use(response => {
<!-- // 对响应数据做点什么 -->
console.log(response);
this.isShow = false;
return response;
}, function(error) {
<!-- // 对响应错误做点什么 -->
return Promise.reject(error);
});
this.$axios.get('http://127.0.0.1:8888')
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
})
}
}
};
Vue.prototype.$axios = axios;
new Vue({
el: '#app',
data() {
return {
}
},
template: ` `,
components: {
App
}
});
</script>
</body>
</html>
能完成所有常用的功能:
安装:
npm i webpack-cli -g
index.js
//jquery存放在本地
import $ from './libs/jquery'; // 引入jquery
//jquery存放在node_modules
import $ from 'jquery';
$(function(){
alert(a);
})
webpack.config.js
model.exports{
//模式
mode: 'development',
//入口
entry: './src/js/index.js',
//输出
output: {
path: path.resolve(__dirname,'build'),
filename: 'build.js'
}
}
webpack是一个现代JavaScript应用程序的静态模块打包器。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fa7einSe-1585806966684)(C:\Users\A\AppData\Roaming\Typora\typora-user-images\image-20200331142837324.png)]
(function (root, factory) {
if (typeof exports === 'object') {
module.exports = factory(); //commonjs环境下能拿到返回值
} else if (typeof define === 'function' ) {
define(factory); //define(function(){return 'a'}) AMD
} else {
window.eventUtil = factory();
}
})(this, function() { //this相当于传的root
// module 返回给factory
return {
//具体模块代码
addEvent: function(el, type, handle) {
//...
},
removeEvent: function(el, type, handle) {
},
};
});
手动实现vue-cli脚手架工具,同时也学习webpack的使用
npm install [email protected] -D
安装全局webpack:
npm install webpack -g
// 整个程序的入口文件
import Vue from './vue.js'
import App from './App.js'
// 模块整体加载
// import {num,num2,add} from './App.js'
// console.log(num);
// console.log(num2);
// add(3,5);
// import * as object from './App.js'
// console.log(object);
// console.log(object.num);
// console.log(object.num2);
// add(3,5);
new Vue({
el:'#app',
components:{
App
},
template:` `
});
var App = {
template:`
我是一个入口组件
`
};
//1. 声明并导出
export var num = 2; //作为一整个对象key导出
//2. 声明再导出
var num2 = 4;
export {num2};
//3.抛出一个函数
export function add(x,y) {
return console.log(x+y);
}
//4.抛出一个对象
export default App;
{
"name": "29_module",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"build": "webpack ./main.js ./build.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^3.12.0"
}
}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>title>
head>
<body>
<div id="app">div>
<script type="text/javascript" src="./build.js">script>
body>
html>
3.上面那种方法也可以通过webpack直接运行
完整笔记文档链接