一、vue的基础使用
1.双大括号插值法 {{xxx}}
2.有tempalte的情况下,加载template的内容
3.引用vue,npm install vue的包后,通过script标签引入
4.常用样式:
let vm=new Vue({
el:".demo",
data:function(){
return{
//数据属性
msg:"这是一段测试的数据"
}
},
template:`
<div class="tem"></div>
`,
methods:{
//里面放v-on绑定的时间函数
cilckHander(e){
console.log(e);
}
}
})
5.Vue的具体使用和API文档:Vue的中文官网
二、Vue的指令系统
1.v-text 相当于innerText
<a v-text="msg" href="http://" target="_blank" rel="noopener noreferrer""></a>
2.v-html 相当于innerHTML
<div v-html="msg2"></div>
3.v-show 相当于dispaly属性
<i v-show="radom>0.5">随机显示{{radom}}</i>
4.v-if v-else 数据属性值对应的值如果为假,则不在页面中渲染 相当于appendChild()、removeChild()
<p v-if="isTrue">渲染true</p>
<p v-else>渲染false</p>
5.v-bind 绑定标签上的属性(内置属性或自定义属性) 简写可省略v-bind
//绑定内置属性
<div class="box" v-bind:class="{active:isTrue}"></div>
<img src="" alt="图片加载失败" :src="imgSrc"></img>
//绑定自定义属性
<div v-bind:aaa="text"></div>
//没有冒号后的判断时,变量不需要{}括起来
6.v-on 给标签绑定事件 简写用@
<div class="box" v-on:click='clickHander'></div>
<div class="box" @click='clickHander'></div>
7.v-for 循环遍历,可以是对象,数组等
<ul>
//遍历对象数组
<li v-for="(item,index) in lists">
id: {{item.id}}<br>
name: {{item.name}}<br>
age: {{item.age}}<br>
index: {{index}}
</li>
//遍历一个对象内的key-value
<li v-for="(value,key) in person">
{{key}}: {{value}}
</li>
</ul>
详细指令使用:Vue指令系统
三、组件
1.局部组件
a.局部组件声明,组件内的data一定是个函数
let APP = {
data: function () {
return {
msg: "这是一段data数据"
}
},
template: `
<ul>
<li> {{msg}} </li>
<li> {{msg}} </li>
<li> {{msg}} </li>
</ul>
`
};
b.局部组件挂载,挂载在Vue的components上
components: {
APP
},
c.局部组件使用,只能在template中引用
template: `
<div class="tem">
<APP/>
</div>
`
2.全局组件
使用Vue.component(name,options),第一个参数是组件名,第二个是组件具体内容,与局部组件一样
let my = Vue.component("Mybtn", {
data: function () {
return {
}
},
template: `
<button>按钮</button>
`
});
全局组件的使用同局部组件一样
3.通过prop挂子通信
父组件向子组件传递数据
a.想给父组件中绑定自定义的属性
b.在子组件中使用props接收父组件传递的数据
c.可以在子组件中任意使用
/*------子组件------*/
Vue.component('Child',{
template:`
<div>
<p>这是一个子组件</p>
<input type="text" v-model="childData"/>
<p>childData:{{childData}}</p>
</div>
`,
// 通过props接收数据
props:['childData']
});
/*------父组件------*/
Vue.component('Parent',{
data(){
return{
msg:'这是来自父组件的数据'
}
},
// 将要传递的数据绑定在子组件属性上
template:`
<div class="tem">
<p>这是一个父组件</p>
<Child :childData="msg"/>
<p>msg:{{msg}}</p>
</div>
`
});
注:对于多层组件之间的数据传递,可以使用v-bind='$attrs',传递数据的值($attrs的值就是props的值)
4.通过事件向子组件发送消息
子组件向父组件传递数据
a.在父组件绑定自定义的事件childHander
b.在子组件中 触发原生事件 在函数中使用$emit触发父组件当中自定义的事件childHander
c.this.$emit('要触发的事件名',传递数据);//this.$emit('childHander',val);
//这里有子组件与父组件的数据双向传递
/*-------子组件------*/
Vue.component('Child', {
data:function(){
return{
msg:'这是子组件的数据'
}
},
template: `
<div>
<p>这是子组件</p>
<input type='text' v-model="childData" @input="valueChange(childData)">
</div>
`,
methods:{
valueChange(val){
this.$emit('childHander',val);
}
},
props:['childData']
});
/*-------父组件------*/
Vue.component('Parent', {
data: function () {
return {
msg: '这是一条来自父组件的数据'
}
},
template: `
<div>
<p>这是父组件</p>
<Child :childData="msg" @childHander='childHander'/>
<p>msg:{{msg}}</p>
</div>
`,
methods:{
childHander(val){
this.msg=val;
}
}
});
let vm = new Vue({
el:'.demo',
data(){
return{
}
},
template:`
<div>
<Parent/>
</div>
`
})
注:1.对于多层组件数据传递,在中间层组件数据传递可用v-on='$listener' 代替中间层的事件绑定。
2.在中央事件总线创建公共的类中,可以配套使用$emit():触发自定义的事件和$on():绑定自定义事件,绑定到同一个实例化对象中(可以定义一个中央示例化对象),用于兄弟间组件传值
3.关于传值总结:
三、具名插槽
slot的使用:<slot name='one'></slot>与<标签 slot='one'>第一个插槽</标签>对应
let APP = {
template: `
<ul>
<slot name='one'></slot>
<slot name='two'></slot>
</ul>
`
};
let vm = new Vue({
components: {
APP
},
template: `
<div class="tem">
<APP>
<li slot='one'>第一个插槽</li>
<li slot='two'>第二个插槽</li>
<APP/>
</div>
`
})
四、过滤器
过滤器的作用:为页面中数据进行添油加醋的工作
1.步骤
a).声明过滤器 局部过滤器/全局过滤器
b).使用过滤器 {{数据|过滤器名字}}或v-bind里面 ' | '为通道符
2.局部过滤器 filters:{}
let Filter1={
data:function(){
return{
msg:'这是一条来自Filter的数据',
message:''
}
},
template:`
<div>
<input type='text' v-model='message'></input>
<h3>{{message|filterMessage}}</h3>
<h4>{{msg|changeMsg('这是全局过滤器')}}</h4>
</div>
`,
filters:{
filterMessage:function(val){
if(val.trim()){
return '¥'+val;
}
}
}
}
3.全局过滤器 Vue.filter(过滤器名字,函数);
Vue.filter('changeMsg',function(val,arg){
return arg+' '+val.split('').reverse().join('');
})
注:所有过滤器中的函数中,第一个参数都是通道符号 ‘|’ 前的数据(要过来操作的数据),后面的参数为函数传入的参数值
五、监听数据
watch监听的是单个属性
1.简单监视 基本的数据类型
<body>
<div class="demo">
<input type="text" v-model='msg'>
<h3>{{msg}}</h3>
</div>
</body>
<script type="text/javascript">
let vm=new Vue({
el:'.demo',
data:function(){
return{
msg:'这是一段数据'
}
},
watch:{
msg:function(newV,oldV){
console.log(newV,oldV);
}
}
})
</script>
2.复杂监视 复杂的数据类型
<body>
<div class="demo">
<button @click="arrayM[0].name='Roy'">变化</button>
<h3>{{arrayM[0].name}}</h3>
</div>
</body>
<script type="text/javascript">
let vm=new Vue({
el:'.demo',
data:function(){
return{
arrayM:[{name:'jack'},{name:'lan'}]
}
},
watch:{
arrayM:{
deep:true,//深度监听
handler:function(nV,oV){
console.log(nV[0].name);
}
}
}
})
</script>
六、计算属性 (监听的数据不在data里面)
1.定义监听数据方法 computed
computed: {
musicSrc: function () {
return this.musicData[this.currentIndex].musicsrc;
}
}
2.使用监听数据
<audio :src="musicSrc" autoplay controls loop=-1></audio>
<p style="margin: 10px;">正在播放:{{musicSrc}}</p>
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./node_modules/vue/dist/vue.min.js" type="text/javascript"></script>
<style>
*{
padding: 0;
margin: 0;
}
ul>li{
background-color: rgba(0, 255, 255, 0.61);
margin: 10px 10px;
border-radius: 5px;
padding: 10px;
list-style: none;
}
.active{
background-color: yellow;
}
</style>
</head>
<body>
<div class="demo">
<audio :src="musicSrc" autoplay controls loop=-1></audio>
<br>
<p style="margin: 10px;">正在播放:{{musicSrc}}</p>
<ul>
<li v-for='(item,index) in musicData' @click='changeMusic(index)' :class='{active:currentIndex==index}'>
歌曲名:{{item.name}}<br>
地址:{{item.musicsrc}}
</li>
</ul>
</div>
</body>
<script type="text/javascript">
let vm = new Vue({
el: '.demo',
data: function () {
return {
musicData: [
{ id: 1, name: '戒烟', musicsrc: './audio/戒烟.mp3' },
{ id: 2, name: '时间飞行', musicsrc: './audio/时间飞行.m4a' },
{ id: 3, name: '牛奶面包', musicsrc: './audio/牛奶面包.mp3' },
{ id: 4, name: '离骚', musicsrc: './audio/离骚.mp3' }
],
currentIndex:0
}
},
computed: {
musicSrc: function () {
return this.musicData[this.currentIndex].musicsrc;
}
},
methods:{
changeMusic(num){
this.currentIndex=num;
this.isPlay=num;
// let current=document.querySelector("ul").childNodes;
// for(var i=0;i<current.length;i++){
// current[i].setAttribute('class','');
// }
// current[num].setAttribute('class','active');
}
}
})
</script>
</html>
七、生命周期
代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./node_modules/vue/dist/vue.min.js" type="text/javascript"></script>
</head>
<body>
<div id="demo">
<!-- Vue内置组件<keep-alive></keep-alive>能在组件切换过程中间状态保留在内存中。防止重复渲染 -->
<keep-alive>
<app-template v-if='isAdd'></app-template>
</keep-alive>
<br>
<button @click='isAdd=!isAdd'>改变生死</button>
</div>
</body>
<script type="text/javascript">
//局部组件
let appTemplate={
data:function(){
return{
msg:'这是来自局部组件APP的数据'
}
},
template:`
<div class='app'>
<div>{{msg}}</div><br>
<button @click='changeHandler'>改变内容</button>
</div>
`,
methods:{
changeHandler(){
this.msg='TFBOYS';
}
},
beforeCreate:function(){
//组件创建之前
console.log(this.msg);//undefined
},
created:function(){
//组件创建之后 在created这个方法中可以操作后端数据,数据驱动视图
//应用:发起ajax请求
console.log(this.msg);//'这是来自局部组件APP的数据'
},
beforeMount:function(){
//数据挂载到DOM之前
console.log(document.querySelector('#demo'));
},
mounted:function(){
//数据挂载到DOM之后 会调用Vue作用以后的DOM
console.log(document.querySelector('#demo'));
},
beforeUpdate:function(){
//在更新DOM之前 调用该钩子 应用:可以获取原始的DOM元素
console.log(document.querySelector('#demo').innerHTML);
},
updated:function(){
//在更新DOM之后 调用该钩子 应用:可以获取最新的DOM元素
console.log(document.querySelector('#demo').innerHTML);
},
beforeDestroy:function(){
//组件销毁之前
console.log('beforeDestroy:');
},
destroyed:function(){
//组件销毁之后
console.log('destroyed:');
},
activated:function(){
console.log('组件被激活了');
},
deactivated:function(){
console.log('组件停用了');
}
}
let vm=new Vue({
el:'#demo',
data:function(){
return{
msg:'这是来自Vue的数据',
isAdd:true
}
},
components:{
appTemplate
}
});
</script>
</html>
注意:
1.组件命名:小写html页面加载没有问题,大写如:appTemplate,引用时要变成<app-template/>
2.上述代码如果组件引用换成在Vue的template里面,结果会巨大变化(DOM元素挂载与template加载时间上不一样)
3. Vue内置组件<keep-alive></keep-alive>能在组件切换过程中间状态保留在内存中。防止重复渲染。使用了<keep-alive></keep-alive>,beforeDestroy和destroyed方法将失效,改为采用activated和deactivated方法
八、 获取DOM元素
1.给DOM元素添加ref属性;如:ref='mydom'
2.通过实例对象的$refs内置属性获取DOM元素;如:this.$refs.mydom
3.上述步骤只能获取更新前的DOM元素,如果页面发生了变化,则要是用$nextTick(
)方法来获取更新后的DOM元素
let myTemplate={
data:function(){
return{
msg:'这是来自myTemplate的数据',
isShow:false
}
},
template:`
<div class='mytem'>
<p ref='myp'>{{msg}}</p>
<input type='text' v-show='isShow' ref='input'/>
</div>
`,
mounted:function(){
this.isShow=true;//更新了页面
this.$nextTick(function(){
this.$refs.input.focus();
}),
//$nextTick与放在updated里的效果相同
// updated:function(){
// this.$refs.input.focus();
// }
}
}
九、路由
1.引包
2.创建VueRouter对象
3.配置路由规则
4.将路由挂载到实例对象Vue上
let router=new VueRouter({
routes:[
{
path:'/login',
name:'login',
component:login
},
{
path:'/register',
name:'register',
component:register
}
]
});
5.使用路由 router-link==>a to==>href
template:`
<div>
<router-link to='/login'>登入</router-link>
<router-link to='/register'>注册</router-link>
<router-view>hhh</router-view>
</div>
`
6.路由的参数
a). path:'/login/:id' :to="{name:'login',params:{id:1}}"
b). path:'/register :to="{name:'register',query:{userId:1}}"
let router=new VueRouter({
routes:[
{
path:'/login/:id',
name:'login',
component:login
},
{
path:'/register',
name:'register',
component:register
}
]
});
let vm=new Vue({
router,
template:`
<div>
<router-link :to="{name:'login',params:{id:1}}">登入</router-link>
<router-link :to="{name:'register',query:{userId:1}}">注册</router-link>
<router-view>hhh</router-view>
</div>
`
})
7.参数获取
在相应的组件(配置到路由里面的组件)的created生命周期里查找this.$route.params.xxx或this.$route.query.xxx xxx
8.嵌套路由 children:[{路由配置},{路由配置}]
let router=new VueRouter({
routes:[
{
path:'/login/:id',
name:'login',
component:login,
children:[
{
path:'/login/music',
name:'music',
component:music
},
{
path:'/login/movie',
name:'movie',
component:movie
}
]
},
{
path:'/register',
name:'register',
component:register
}
]
});
总结
9.动态路由
实现切换到相同组件,但是数据不一样,用watch监听$route的变化来获取相同组件切换携带的参数值
//公共组件
let conDec={
data:function(){
return{
msg:''
}
},
template:`
<div>
我是{{msg}}
</div>
`,
created:function(){
this.msg=this.$route.params.id;//获取不同组件切换携带的参数
},
watch:{
'$route'(to,from){
this.msg=to.params.id;//获取相同/公共组件之间切换携带的参数
}
}
}
let Home={
template:`
<div>
这是主页
<div>
<router-link :to="{name:'condec',params:{id:1}}">前端</router-link>
<router-link :to="{name:'condec',params:{id:2}}">后端</router-link>
<router-view></router-view>
</div>
</div>
`
}
let router=new VueRouter({
routes:[
{
path:'/home',
name:'home',
component:Home,
children:[
{
path:'/home/:id',
name:'condec',
component:conDec
}
]
},
{
path:'/login',
name:'login',
component:Login
}
]
});
注:如果要在组件切换时保存组件状态,可以采用<keep-alive></keep-alive> 保存组件状态
10.路由meta的使用和权限限制
a).跳转需要权限(如登入方可查看)的路由配置中添加meta:{auth:true}
b).通过router.beforeEach((to,from,next)=>{判断to.meta.auth和localStorage是否为空,来控制路由跳转权限})
c).localStorage.setItem('user',{name:this.name,password:this.password}) 给本地存储添加数据
localStorage.getItem('user'); 获取本地存储数据 localStorage.clear(); 清空本地存储的数据
代码实现如下:
<body>
<div class="demo">
<router-link :to="{name:'home'}">首页</router-link>
<router-link :to="{name:'blog'}">博客</router-link>
<router-link :to="{name:'login'}">登入</router-link>
<a href="javascript:void(0)" @click='handleOut'>退出</a>
<router-view></router-view>
</div>
</body>
<script>
let Home={
template:`
<div>我是主页界面</div>
`
}
let Blog={
template:`
<div>我是博客界面</div>
`
}
let Login={
template:`
<div>
我是登入界面
<div>
账号:<input type='text' name='name'/><br>
密码:<input type='password' name='password'/><br>
<button @click='handleLogin'>提交</button>
</div>
</div>
`,
methods:{
handleLogin(e){
localStorage.setItem('user',{name:this.name,password:this.password})
// this.$router.options.routes[2].meta.auth=false;
this.$router.push('blog');
}
},
mounted:function(){
if(localStorage.getItem('user')){
alert('你已经成功登入!');
this.$router.push('home');
}
}
}
let router=new VueRouter({
routes:[
{
path:'/',
redirect:'/home'
},
{
path:'/home',
name:'home',
component:Home
},
{
path:'/blog',
name:'blog',
component:Blog,
meta:{
auth:true
}
},
{
path:'/login',
name:'login',
component:Login
}
]
});
router.beforeEach((to,from,next)=>{//权限控制
if(to.meta.auth){
if(localStorage.getItem('user')){
next();
}
else{
next('/login');
}
}
else{//如果访问的不是blog页面auth都是false
next();//避免加载卡顿
}
});
let vm=new Vue({
el:'.demo',
data:function(){
return{
msg:'this is message'
}
},
router,
methods:{
handleOut(){
localStorage.clear();//退出登入
}
}
});
</script>
11.导航守卫
详细使用参考:导航守卫
使用组内守卫实现离开保存的功能
let music_movie = {
data() {
return {
msg: 'music',
answer:{'music':false,'movie':false}
}
},
template: `
<div>
This is {{msg}}<br/>
<button >保存</nutton>
</div>
`,
watch: {
'$route'(to, from) {
this.msg=to.params.idname;
}
}
beforeRouteLeave(to, from, next) {
let currPage=to.params.id
const isSave=this.answer.currPage= window.confirm('Do you really want to leave? you have unsaved changes!');
if (isSave) {
next()
} else {
next(false)
}
}
}
let login = {
data: function () {
return {
msg: '这是登入界面'
}
},
template: `
<div>
{{msg}}
<br>
<router-link :to="{name:'music',params:{idname:'music'}}">音乐</router-link>
<router-link :to="{name:'movie',params:{idname:'movie'}}">电影</router-link>
<router-view></router-view>
</div>
`
}
let router = new VueRouter({
routes: [
{
path: '/login/:id',
name: 'login',
component: login,
children: [
{
path: '/login/:idname',
name: 'music',
component: music_movie
},
{
path: '/login/:idname',
name: 'movie',
component: music_movie
}
]
}
]
});
let vm = new Vue({
el: '.demo',
router,
template: `
<div>
{{msg}}
<br>
<router-link :to="{name:'login',params:{id:1}}">登入</router-link>
<router-view></router-view>
</div>
`
})
十、Axios
详细参考文档:axios中文文档
1.在Vue中使用axios:
1).安装axios包
$ npm install axios
2).将axios绑定在Vue实例对象或者原型对象上
Vue.prototype.$axios = axios;
3).根据axios中文文档使用axios
2.axios的基本使用 (有get或post两种)
sendAjax(){
this.$axios.get('http://api.github.com/users')
.then(res=>{
username=res.data[0].login;
return this.$axios.get(`http://api.github.com/users/${username}/repos`);
})
.then(res=>{
console.log(res.data);
}).catch(err=>{
console.log(err);
})
}
注意:get方式有两种带携带参数的方式(写在url上或者以json对象形式作为参数携带) post方式有一种携携带参数方式(以json对象形式作为参数携带)
3.axios的并发请求 this.$axios.all([getD,postD]).then(res=>{}).catch(err=>{})
handleClick(e){
let urlDefault=`http://api.github.com/`;
let getD=this.$axios.get(`${urlDefault}users`)
let postD=this.$axios.get(`${urlDefault}`,{
id:111
})
this.$axios.all([getD,postD])
.then(this.$axios.spread((res1,res2)=>{
console.log(res1.data);
console.log(res2.data);
})
)
.catch(err=>{
console.log(err);
})
}
}
4.axios的请求和响应 transformRequest和transformResponse
this.$axios({
url: `${urlDefault}users`,
method: 'get',
// `transformRequest` 允许在向服务器发送前,修改请求数据
transformRequest: [function (data, headers) {
// 对 data 进行任意转换处理
return data;
}],
// `transformResponse` 在传递给 then/catch 前,允许修改响应数据
transformResponse: [function (data) {
console.log(data);//等于res.data的内容
return data;
}],
})
.then(res=>{
console.log(res);
})
.catch(err=>{
console.log(err);
})
5.axios拦截器
//添加请求拦截器
this.$axios.interceptors.request.use(config => {
console.log(config);
return config;
}, error => {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
this.$axios.interceptors.response.use(response => {
console.log(`two:${response}`);
return response;
}, error => {
// 对响应错误做点什么
return Promise.reject(error);
});
axios拦截器实现加载动画
//通过控制this.isShow的值控制加载动画的显示与隐藏
handleClick(e) {
let urlDefault = `http://api.github.com/`;
/* 添加请求拦截 请求时isShow为true 显示加载动画 */
this.$axios.interceptors.request.use(config => {
this.isShow=true;
return config;
}, error => {
// 对请求错误做些什么
return Promise.reject(error);
});
/* 添加响应拦截器 响应时isShow为false 隐藏加载动画 */
this.$axios.interceptors.response.use(response => {
this.isShow=false;
return response;
}, error => {
// 对响应错误做点什么
return Promise.reject(error);
});
this.$axios({
url: `${urlDefault}users`,
method: 'get'
})
.then(res => {
console.log(res);
})
.catch(err => {
console.log(err);
})
}