vue
2020-06-05 14:03:14 30 举报
AI智能生成
Vue学习记录
作者其他创作
大纲/内容
vue
Vue基础
1·基本使用-实例属性-指令
1· vue是什么
vue就是一个js框架
vue只关注数据(data),无需操作dom
2· vue的基本使用
1·导包
生产环境用min版本
开发环境用vue.js版本
2·html布局【确定vue使用范围】
{{ message }} 插值语法,将data中的数据放到指定位置
若使用了未定义的数据变量,则报错
3·vue实例化
new Vue({ }) 使用new关键字实例化
el:实际上是执行了querySelector,确定vue使用范围
注意:不能选择body/html
行业规范:使用id ,因为id的唯一性
data:保存数据
data为一个对象,其中的数据为变量,变量可以保存各种数据
3· vue实例属性
el:'选择器'
确定vue使用范围
data:{}
保存数据
methods:{}
保存方法
方法中访问data变量,必须添加this
es6方法简写:add(){ }
this
1·vue中的this就指向new Vue实例化出来的vue对象
let app=new Vue({ //这里面的this就指向app})
2·vue实例化过程中会将data与methods中的数据平铺到vue实例 通过this.属性名/方法名可以直接访问
this.msg 就可以获取data中的msg变量中的数据
this.getMsg 就可以调用methods中的getMsg方法
3·在methods中访问data数据需要添加this,dom访问new Vue不需要加this
{{ msg }} 使用插值语法直接将msg查到指定区域
4·vue会自动修改methods中的方法的this指向,修改为new Vue的实例对象
components:{ }
注册组件
4· vue指令
v-text
v-text=\"值\" ,相当于innerText
1·变量,data中保存的数据
2·js基本运算
3·三元表达式
会覆盖元素内的原内容
简写{{ }} 插值语法
在指定区域插入指定数据,使用插值语法不会替换文本内容
也适用于一句话表达式
若取对象中的数据,使用.语法
v-html
可以解析HTML标签,一般用于富文本
带有标签的字符串叫做富文本
值也适用于一句话表达式
使用场景:接口返回富文本,前端解析
类似innerHTML,原文本也会被替换
v-model
实现表单元素与数据的双向绑定
v-model='变量' 不使用与一句话表达式
在vue中,只要遇到input标签,就可以想到v-model
v-model的修饰符
.lazy
在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy 修饰符,从而转变为使用 change 事件进行同步:
例如在添加用户与编辑用户事件同时共用一个dialog对话框与form表单时,在编辑用户按钮上添加.lazy
编辑用户会读取表单的数据源,而添加用户不会,如果用户点击了确定,但是并没有做任何修改,就不需要发送axios请求
.number
如果想自动将用户的输入值转为数值类型,可以给 v-model 添加 number 修饰符:
将用户输入的内容强制转为数值类型,例如年龄或生日或手机号码等
.trim
如果要自动过滤用户输入的首尾空白字符,可以给 v-model 添加 trim 修饰符:
@ v-on:事件名=function
简短的js或者function ,例如简单的自增自减运算
简写 @
function写在 methods:{} 对象中
<input type=\"button\" value=\"\" @click='add'>
方法名使用' '包裹,不传参可以省略小括号
方法访问data数据,必须添加this
v-on常用修饰符
@事件名.enter
回车修饰符,按下回车触发
@事件名.stop
阻止事件冒泡
@事件名.prevent
阻止默认行为
@事件名.键值
键盘上每个按键都有对应的值
常用事件
click 鼠标单击事件
dblclick 鼠标双击事件
mouseenter 鼠标移入
mouseleave 鼠标移出
focus 获得焦点
blur 失去焦点
load 加载完成
keyup 鼠标弹起
change 监视变化事件
: v-bind:属性名='属性值'
简写 :
绑定指定属性
通过绑定指定属性后可以控制属性值的修改
属性值适用于一句话表达式
对象用法
:class='{类名:boolean}'
boolean为true:添加这个类名
boolean为false:不使用这个类名
同时存在两个类名才生效的css写法
.box.active{ }
中间没有空格
v-for
作用:遍历数据,并渲染列表
v-for=\
item:数组中的每一项
index:数组中每一项的下标
items:遍历的数组
:key
渲染标识
value:对象中每一项的键值
key:对象每一项的键名
index:对象中的序号
Object:遍历的对象
v-for 遍历对象比较少
v-if
v-if='boolean' 值适用于一句话表达式
值为true则渲染
值为false则不渲染
与v-show的区别
v-show是显示,v-show性能高,v-if是渲染,v-if性能低
使用场景
根据某个条件,是否渲染某个标签
例如英雄案例的 v-if 显示 暂无数据
v-else-if
与if-else用法相同
v-else
v-else后不带值
v-cloak
实际上是在标签上定义了一个v-clock属性
在vue实例化完成后,该属性会自动销毁
作用:当作属性选择器使用
[v-cloak]{ display:none}
v-onec
作用:让该标签的所有vue语法只执行一次
v-pre
<pre>这个pre标签的作用是保持文本原样输出,包括多个空格与换行</pre>
v-pre与pre标签相同,不解析vue语法,使用原生的内容
5·vue动画
单元素动画
1·场景: v-if或v-show
2·使用transition 包裹需要动画的元素
3·在transition设置name属性
4·css动画处理
enter:正常显示之前
隐藏->显示
leave:正常显示之后
显示->隐藏
.xxx-enter{ opacity: 0; transform: translateX(-200px); } .xxx-leave-to{ opacity: 0; transform: translateX(200px); }
enter:正常显示之前的过渡动画
leave:隐藏之后显示的过渡动画
5·注意在元素上使用v-if 或v-show ,值为布尔值,<div class=\"box\" v-if='blo'></div> ,根据布尔值的改变 显示或隐藏
多元素动画
1·使用v-if 或 v-show 实现动画
2·使用transition-group 包裹需要动画的元素,且每个元素必须设置key值
3·在transition中添加一个name属性,这个name的属性值为css控制的动画选择器
<transition-group name=\"xxx\"> <div class=\"box\" v-if=\"isShow\" key='div1'></div></transition-group>
xxx是transition的name名
enter-active 进入前
leave-active 离开后
transition 动画过渡属性
.xxx-enter { opacity: 0; transform: translateX(-600px); } .xxx-leave-to { opacity: 0; transform: translateX(600px); }
xxx-enter 进入前的需要进行的动画
xxx-leave-to 离开后需要进行的动画
多个动画进行过渡,使用:nth-child() 选择器处理
2·重要语法使用和概念
6·vue生命周期,都是方法
vue生命周期是什么
vue的生命周期的思想贯穿在组件开发的始终,通过熟悉其生命周期调用不同的钩子函数,我们可以准确地控制数据流和其对DOM的影响;vue生命周期的思想是Vnode和MVVM的生动体现和继承。
根据不同的需求,在指定的生命周期钩子函数中处理数据或者渲染dom
Vue生命周期是指vue实例对象从创建之初到销毁的过程,vue所有功能的实现都是围绕其生命周期进行的,在生命周期的不同阶段调用对应的钩子函数可以实现组件数据管理和DOM渲染两大重要功能。
所有的生命周期本质上都是一个函数
它是自动调用执行,前四个生命周期钩子函数只会执行一次
注意:生命周期钩子函数不是放在methdes中,而是与data,methdes平级的
beforeCreate
创建前, 还不能访问data与methods
此阶段为实例初始化之后,此时的数据观察和事件机制都未形成,不能获得DOM节点。
created(){ }
创建后,可以访问data与methods,但还不能访问vue渲染的dom
进入页面就进行的操作就在这里,例如aixos请求
在这个阶段vue实例已经创建,仍然不能获取DOM元素
beforeMount
渲染前
准备开始渲染dom数据,但是还没有渲染
在这一阶段,我们虽然依然得不到具体的DOM元素,但vue挂载的根节点已经创建,下面vue对DOM的操作将围绕这个根元素继续进行;beforeMount这个阶段是过渡性的,一般一个项目只能用到一两次。
mounted
渲染后
可以访问vue渲染的dom
它是第一个可以访问vue渲染后的dom的生命周期钩子函数
进入页面需要访问dom的操作就在这里调用
mounted是平时我们使用最多的函数了,一般我们的异步请求都写在这里。在这个阶段,数据和DOM都已被渲染出来。
例如iScroll滚动条插件就在mounted中实例化
beforeUpdate
更新前,vue在页面上使用的数据已经修改,但还没有完成数据渲染
在这一阶段,vue遵循数据驱动DOM的原则;beforeUpdate函数在数据更新后虽然没立即更新数据,但是DOM中的数据会改变,这是Vue双向数据绑定的作用。
updated
更新后
数据已修改,且页面已完成更新
在这一阶段DOM会和更改过的内容同步。
beforeDestroy
销毁前
在上一阶段vue已经成功的通过数据驱动DOM更新,当我们不在需要vue操纵DOM时,就需要销毁Vue,也就是清除vue实例与DOM的关联,调用destroy方法可以销毁当前组件。在销毁前,会触发beforeDestroy钩子函数。
主体用于善后工作,主体是清理一些不停执行的事件,例如setInterval
可以访问DOM
destroyed
销毁后
在销毁后,会触发destroyed钩子函数。
7·computed:{ }计算属性
用法:computed:{ 计算属性名:(){ 在函数体中处理数据 }}
与data,methods平级
1·使用场景:依赖一个或者多个数据,生成一个新的数据
2·计算属性本质上是一个函数,将结果return出来
3·可以当作属性使用
使用插值语法直接插入计算属性名
4·计算属性是实时响应的,会根据数据变化而变化
5·计算属性传参
1·在方法中return一个方法
2·在插值语法调用return的方法,并传递参数
3· return的值就是计算属性的值
8·ref 获取dom
1·在需要获取的dom元素上定一个ref属性
ref='属性值'
<p ref='pbq'></p>
2·使用$refs.属性名
this.$refs.pbq
不要忘了this
9· this.$nextTick()
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
1·这是vue自带的一个异步执行方法,与setTimeout计时器相似,只是不需要添加时间
2·做了一个异步处理,当数据渲染完成后就会执行
3·用法:
this.$nextTick(()=>{ //需要执行的异步代码 })
4·作用:
例如:iScroll滚动条插件的异步刷新,当数据更新之后就会触发需要执行的异步代码
10.组件
1·组件的基本使用
将某个界面或者功能封装起来,就叫做组件
特点:
可复用,易维护,利于多人协同开发
.vue后缀
template
写HTML结构,通常用一个div包裹全部元素
script
写JS逻辑,包含data,methodes,生命周期钩子函数等都写在这里
style
写css样式
快速生成vue骨架
<vue
2·单组件运行:
vue serve '.vue文件路径'
3·多组件运行,组件套组件
1·导入组件
import 组件名 from \"组件路径\";
2·注册组件
3·使用组件
在template中 以组件名的标签直接插入
<组件名></组件名>
4· export default
输出
每个js文件 只能有一个 export default,但是可以有多个export
5· import 名字 form 路径
输入
接收export
import { 名字 } form 路径
名字需要对应,且使用{ } 花括号包裹, 原理是解构赋值
6· 在组件中使用插件
1·装包
npm i axios
2·导包
import axios from \"axios\"
3·用包
axios({url:\"xxx\"}).then(res=>{})
7·组件中传值
1·父传子
1·在子组件标签上引用 ref='值'
<组件名 ref=\"xxx\"></组件名>
2· 通过引用 this.$refs.值 访问子组件this
2·子传父
this.$parent
3·props
使用场景: 例如多个组件都需要使用到的轮播图,就可以用props传递
1·父组件传值子组件
1·在子组件标签上定义一个属性 属性名=“要传给子组件的值”
11·脚手架vue-cli
什么是脚手架
1·可以自动快速搭建vue项目架构
2·节省人工搭建时间
1·全局安装
npm install -g @vue/cli
2·查看版本
vue -V // 如果安装成功会返回:@vue/cli 4.0.5类似这样的版本信息
3·安装组件依赖包
npm install @vue/cli-service-global -g
4·脚手架创建与运行
1·新建一个文件夹,不允许有中文/大写 ,例如playmusic
2·在playmusic目录下运行终端命令 vue create playmusic-cli ,创建完毕后会多出一个playmusic-cli文件夹
3· 使用cd命令 进入playmusic-cli文件夹
4· 启动脚手架 npm run serve
5·文件说明
12·编程式导航
使用路由地址进行跳转,用js改变
实际就是通过hash值变化实现了组件控制
1·this.$router.push('路径')
可以在路径中拼接参数
$router 为路由实例对象
2·this.$route.query.参数名
获取传递的参数
$route 为当前路由对象
3· <a herf='#/home'> home </a>
可以使用a标签跳转
4· <router-link to='/home'> home </router-link>
router-link不用写#号
实际上也是渲染成一个a标签
13·过滤器
1·使用某个方法,过滤出服务器返回的数据中需要的数据 ,这个方法就是过滤器
3·使用方法
filters: { 过滤器名字(value) { return 返回值 } }
value为需要过滤的数据
value.map(item=>{ //过滤条件 })
<div class=\"time\">{{value | 过滤器名字 }}</div>
4·使用场景
黑云音乐的过滤歌手
黑云音乐的过滤时间戳
5·全局过滤器
1·在main.js中定义
2·挂载在Vue原型
注意过滤器名字使用引号包裹
实例
3·使用方法与局部过滤器一致 使用管道符 |
14·作用域插槽 v-slot
1·仅限用于 <template>
2·缩写 #
15·cli环境变量
环境变量:在项目中所有组件都可以访问,类似于 全局变量
使用场景: 黑马面面项目中的验证码图片, 可以直接设置地址而不需要通过axios处理
官方地址
https://cli.vuejs.org/zh/guide/mode-and-env.html
1·在项目根目录 创建( .env.production )文件,注意不是src目录
2· 定义环境变量的要求:
VUE_APP_变量名=变量值
必须以VUE_APP_开头
变量名也必须大写,例如:VUE_APP_HELLO='你好'
3·访问环境变量
通过process.env.VUE_APP_HELLO访问
4·只要.env.production文件有改动,必须重启项目,环境变量才生效
3·axios,router,vuex,iScroll,element-ui ,NProgress,lodash
5· axios
1·axios也是一种ajax请求,比jQuery的ajax方便,体积小,axios只做接口请求
科技的驱动力是懒
2·使用步骤
1·导入或安装axios
2·get请求
可以在url后面拼接参数,也可以使用{ params:{ //也可以在这里输入参数 num:10 }}
.then请求成功的回调函数
res :成功返回的数据
在这个回调中处理数据
注意处理数据时的this ,直接使用箭头函数就OK
.catch请求失败的回调函数
err:错误信息
注意:使用(=>{ })箭头函数没有this ,使用function的话this指向window
3·post请求
与get请求相似,只不过参数直接写在对象中
4·config(配置项)模式
method 不写默认是get请求方式
params:{name=10}
gei请求也可以直接在请求地址url后拼接 ?参数名=参数值
data:{id=111}
注意get请求参数与post请求参数的不同
注意参数要带引号 ‘’ 包裹
整合了get与post请求方式
5·配置axios基地址
axios.defaults.baseURL='基地址'
6·全局使用axios
挂载到Vue原型,使用this访问
Vue.prototype.$axios = axios
访问: this.$axios.请求方法...
3·axios.create({ })
创建一个axios实例,可以理解为将axios复制一份出来,并且可以设置一些共有的属性,例如基地址,请求头等等
创建了实例之后,使用该实例发送请求,就不用携带请求与基地址了
4·axios拦截器
概念:每次使用axios发送请求时,都将这个请求拦截下来,加上我们自己的配置,再让它发出去
一次性解决每次请求都要添加token请求头
//设置拦截器 如果有token就在请求头带上token $axios.interceptors.request.use( config => { if(getToken()){ config.headers.token = getToken(); } return config })
interceptors:拦截器
request:请求
use:使用
config:配置
getToken: 自己封装的获取token方法
headers:请求头
token:请求字段
路由 vue-router
路由基本使用步骤
1· vue create route
创建脚手架,route是项目名
2· npm i vue-router
安装router路由插件
3·import VueRouter from 'vue-router'
在mian.js文件中导入router插件
4·Vue.use(VueRouter)
注册router插件
5·const router=new VueRouter({ })
实例化路由
在实例化路由中配置路由信息
注意这里的component别写错
7·<router-view></router-view>
在父组件App.vue 使用路由占位符
这步容易忘
路由视图,如果标签中没有任何内容 可以写成但标签的形式 <router-view/>
8· npm run serve
在指定目录 运行项目
9·路由重定向redirect
使用场景:用户未登录直接通过路径地址访问,将访问地址重定向到登陆页
使用方法:
在路由配置中加入redirect属性 ,值为重定向的路由地址
10·路由提取
1·在src目录下新建router文件夹
2·在router文件夹中新建index.js
3·导入vue 导入路由 注册路由
import Vue from 'vue'import VueRouter from 'vue-router'
Vue.use(VueRouter)
4·实例化路由
const router = new VueRouter({ routes: [ //在这里配置路由 ]})
5·暴露路由
export default router
根据不同的路径进行不同的组件切换
在不刷新页面的情况下进行页面的跳转
局部刷新
根据hash值的改变,切换对应的组件
hash值
地址栏 #号之后的都是hash值
路由传参与接收
this.$router.push('要传递的路由地址?参数名=参数值')
this.$route.query.参数名
例:
this.$router.push(`/songsList?keywords=${this.inputVal}`);
this.$router.push('/');
触发事件,跳转到首页
'/' 为根目录 就是首页
url: `http://183.237.67.218:3000/mv/detail?mvid=${this.$route.query.mvid}`
接收另一个组件传递的参数,并根据参数发送axios请求
路由导航守卫
控制路由跳转过程中发生某些事
beforeEach : 在路由发生跳转之前
主要用于登陆验证或检测token
to :路由跳转的目标地址
form:即将要跳转离开的路由地址
1.但凡涉及到有next参数的钩子,必须调用next() 才能继续往下执行下一个钩子,否则路由跳转等会停止。
2.如果要中断当前的导航要调用next(false)。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到from路由对应的地址。(主要用于登录验证不通过的处理)
3.当然next可以这样使用,next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。意思是当前的导航被中断,然后进行一个新的导航。可传递的参数与router.push中选项一致。
4·如果不调用next() 则路由不会通行
使用实例
导航守卫要写在router对象实例之后
一般处理一些进入页面之后的事件。例如登陆的转圈圈特效,登陆成功跳转之后关闭该特效
嵌套路由 children
嵌套路由指的是在渲染的路由组件页面中包含了下级路由渲染出口(<router-view>),浏览器的URL 中各段动态路径也按某种结构对应嵌套的各层组件
简单来说就是一个大路由中,嵌套了N个小路由 ,例如一个div中嵌套了N个div
子路由路径不添加 /
不添加 / 在访问是可以清晰知道是哪个路由的子路由
在配置路由的对象中,添加一个children:[] 数组,嵌套的子路由都写在这个children:[]数组中,子路由与正常路由写法一样 { path: 路径component: 组件名}
路由重定向redirect
redirect :重新导向
使用场景:用户访问根目录' / ' , 将根目录重定向到login登陆页
同样写在routes对象中
路由白名单
可以直接放行的页面,例如:注册,广告,产品展示等 。。。 不需要做登陆判断
const whiteList = [ //需要过滤的路径 ]
if(whiteList.includes(to.path)) { next() }
在beforeEach前置守卫中判断
如果要跳转的路径包含在白名单数组中,不需要做判断,直接放行
路由元信息 meta:{ }
简单来说就是给某个路由添加上标识信息
meta : { test : ' 测试' }
获取1:在路由内部使用 this.$route.meta.test
获取2:在前置路由守卫beforeEach中使用 to.meta.test / from.meta.test
vuex
vuex是什么
vue是根据数据来执行的框架,数据太多就不好管理,每个组件之间想要通过父组件App来操作数据,很不方便,所以就把数据抽离出来,单独放在一个地方,这个地方就是vuex
官网:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。
state,驱动应用的数据源;view,以声明方式将 state 映射到视图;actions,响应在 view 上的用户输入导致的状态变化。
vuex的核心就是 store(仓库),仓库就是用来存东西的,存的就是数据
基本使用
1·下载 npm i vuex
2·导入->注册->实例化->注入vue
import Vuex from 'vuex'
Vue.use(Vuex);
const store = new Vuex.Store({ state: { //在state存放数据 }})
注入vue之后,子组件可以通过$this.store访问该store实例对象
state:{ }
保存属性的地方
子组件访问数据的方法
this.$store.state.属性名
在计算属性中添加
computed: { bankName() { return this.$store.state.bankInf.bankName; }
如果要操作state中的数据,使用mutations来操作,这样在devtools工具中可以直接追踪数据的改动
getters:{ }
处理数据的地方,类似于vue实例的computed计算属性,getters也可以叫做stroe的计算属性,【依赖一个或者多个值,产生新的值】
新的值随着依赖的值变化而变化
注意这里的写法,getters是一个对象,里面的是一个saleProducts对象,保存着一个形参为state的方法
state就是store保存数据的地方,state为计算属性的第一个参数,访问到了state就可以对其中的数据进行操作了
mutations:{ }
保存方法的地方,类似vue实例中的 mounted,官网:【更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。】
第一个参数state 是保存数据的容器
第二个参数payload是自定义的参数
子组件触发mutations中的方法
commit:提交
必须使用.commit('要触发的方法名',自定义的payload参数) ,要触发的方法名必须一致
//commit : 提交 ,同步执行
actions:{ }
类似于mutations,区别在mutations是同步的,无法接受异步,而异步的操作就在actions中处理
// context -> mutations -> minusPrice
context就是mutatins ,再通过mutatins中的minusPrice函数处理数据
actions中不是处理数据的方法,而是将处理数据的方法变成异步执行
子组件触发actions中的方法
必须使用dispatch('方法名',自定义的payload参数)
//dispatch : 派遣,异步执行
相当于:子组件调用actions中的方法,actions中的方法再调用mutatins中的方法处理数据
Modules
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割
子主题 8
iScroll滚动条插件使用
1·导入iScroll.js
<script src=\"../iscroll.js\"></script>
2·布局
3层结构 div>ul>li
<div class=\"wrapper\" id=\"wrapper\"> <ul> <li>10</li> </ul> </div>
设置css
.wrapper { width: 300px; height: 200px; border: 1px solid red; overflow: hidden; position: relative; }
3·实例化,选择dom确定使用范围,并配置iScroll
在mounted生命周期钩子函数中实例化
允许使用鼠标滚动
scrollbars: true
显示滚动条
4·设置定位给div
position: relative;
5·刷新
使用setTimeout定时器
this.myIscroll.refresh()
refresh:刷新,更新
使用this.$nextTick(()=>{ })也可以
element-ui
1·安装
npm i element-ui
2·在main.js导入
import ElementUI from 'element-ui';import 'element-ui/lib/theme-chalk/index.css'; Vue.use(ElementUI);
3·根据需求在官网找对应的组件代码
https://element.eleme.cn/#/zh-CN/component/quickstart
4·使用数据 驱动组件
NProgress 进度条
1· 下巴导包
$ npm install --save nprogress
import NProgress 'nprogress'
导入css样式 import 'nprogress/nprogress.css'
2·用包
只要跳转就触发进度条的话,将进度条放在路由中, beforeEach前置守卫开启进度条,afterEach后置守卫结束进度条
NProgress.start() //开始
NProgress.done() //结束
lodash
一个很牛逼的插件,还没学会
案例
1· 简单的英雄人物搜索demo
1·input搜索框
v-model='heroName'
@keyup.enter='search'
.enter :事件修饰符
2·buttun按钮
@click='search'
3· 渲染英雄姓名
{{ hero[heroIndex].name }}
4·渲染英雄故事
v-text='hero[heroIndex].story'
5· data:{}
heroName:'塞拉斯'
定义变量保存input搜索框的内容,默认为塞拉斯
heroIndex:0
定义变量保存数据下标,搜索方法根据该下标渲染对应数据
6· methods:{}
search(){}
搜索英雄方法
1·使用for循环遍历heroList数据
2·使用if条件判断heroList.name 是否包含input搜索框的值【 使用es6语法 :includes 】
if (this.heroList[i].name.includes(this.heroName))
3· 将heroIndex的值改为i
this.heroIndex=i
⚠️ 注意:在methods方法中访问data ,必须添加this
2· 简单的轮播图
1·默认展示第一张图
:src='arr[imgIndex]'
2·下一张点击功能
@click='next'
3·上一张点击功能
@click='perv'
4· data:{ }
imgIndex:0
保存图片下标
5· methods:{ }
next() { this.imgIndex++ if (this.imgIndex > this.arr.length - 1) { this.imgIndex = 0; } }
点击下一张触发,图片下标自增1,使用if判断当前图片下标是否大于数组长度-1 ,是的话把图片下标改为0,从头开始
perv() { this.imgIndex-- if (this.imgIndex < 0) { this.imgIndex = this.arr.length - 1; } }
点击上一张触发,图片下标自减1,使用if判断当前下标是否小于0,是的话把图片下标改为数组长度-1,从最后开始
3·完整英雄人物demo
1· 循环遍历hero数据,渲染到li标签
<li v-for=\
2·li标签注册点击事件,并传入index
@click='liClick(index)
3·在data中新建变量heroIndex 用于保存当前点击的li列表下标
4·在methods中处理liClick(index)点击方法,并把index保存到heroIndex
liClick(index) { this.heroIndex = index; }
5·使用插值语法,配合heroIndex下标变量渲染 数据
英雄姓名:{{ hero[heroIndex].name }}
英雄图片:<img :src=\"hero[heroIndex].img\" alt=\"\">
英雄特征:<h5>{{ hero[heroIndex].roles.join(' ')}}</h5>
这里渲染的是一个数组,使用join(' ') 转化为字符串
英雄故事:<div class=\"story\" v-html='hero[heroIndex].story'></div>
数据中包含富文本,使用v-html渲染
6· 使用v-bind对象法, 在li列表绑定active类名
:class='{active:heroIndex==index}'
如果heroIndex等于当前的li下标,添加active类名,反之不添加
7·input搜索框与butto按钮点击搜索事件
1·在data中定义变量inputVal,保存input搜索内容,默认为''
inputVal:''
2·input标签使用v-model绑定inputVal,添加keyup事件,search为搜索方法
<input class=\"search\" type=\"text\" placeholder=\"请输入英雄名称进行搜索\" @keyup.enter='search' v-model='searchVal'>
3·button按钮注册点击搜索事件,search为搜索方法
4·methods中根据inputVal变量编写search方法
search(){ this.searchVal=this.inputVal; for(let i=0;i<this.hero.length;i++){ if(this.hero[i].name.includes(this.searchVal)){ this.heroIndex=i; } } }
1·在data中定义新的变量保存搜索内容,作用是中断keyup的搜索
searchVal:''
2·触发点击事件后赋值给中断变量
this.searchVal=this.inputVal;
3·使用for循环遍历hero数据
4·if判断当前遍历的hero每一项的name属性中是否包含searchVal搜索内容,包含的话将下标i赋值给heroIndex
includes:是否包含某个条件,包含则返回该项
修改了heroIndex就会修改全局的渲染数据,完成搜索事件
5·li使用v-if判断是否渲染
v-if='item.name.indexOf(inputVal)!=-1
判断name属性中是否包含搜索内容
!=-1为包含,包含则渲染,反之则不渲染
8·搜索不到数据时显示 ,暂无数据 div
1·在search()方法中给heroIndex添加值
this.heroIndex=-1;
2·在外层div 使用v-if 判断heroIndex的值
<div class=\"content\" v-if='heroIndex!=-1'>
如果heroIndex=-1 则是没有搜索到数据,没搜索到数据则不渲染,显示下方的 暂无数据div
4·英雄案例网络版本
1·进入页面在created钩子函数调用axios获取英雄列表数据
2·声明变量保存服务器返回的数据并渲染li列表
v-for渲染
注册点击事件 ,liClick方法传递index,id
id在请求英雄详情时使用
添加变量保存index
3·声明getInfo方法,发送axios获取英雄详情
注意:该请求需要英雄id,在liClick方法中调用getInfo并传递id
4·li列表的点击事件处理函数
1·将heroIndex=index
2·根据传递的id,发送axios获取英雄详情
3·声明变量heroInfo保存服务器返回的英雄数据
5·根据heroInfo渲染页面
<div class=\"name\">英雄姓名: {{ heroInfo.name }}</div>
<h5>英雄特征:</h5> <span v-for=\
<div class=\"story\" v-html='heroInfo.story'>英雄故事</div>
<img :src=\"heroInfo.img\" alt=\"\">
6·处理进入页面自动触发点击第一个英雄列表,并渲染页面
1·在created生命周期发送的axios中 ,调用getInfo方法,获取英雄详情数据,传递的id为 【this.heroList[this.heroIndex].id】
7·处理英雄搜索功能
1· button按钮添加点击事件,input搜索框添加键盘事件,v-model进行数据绑定 ,搜索方法为search
2·search()方法
1·清空heroList
this.heroList=[];
为了重新渲染数组,也为了搜索不到数据时显示 暂无数据div
2·重新发送英雄列表请求axios ,参数为inputVal 搜索框搜索内容
8· 优化axios请求
1·需要优化的地方:已经获取到的英雄详情,再重新点击也需要重新发ajax,可以使用一个变量保存已经获取过的英雄详情
2·声明变量heroInfoArr=[ ] 一个空数组
3·把获取到的英雄详情push到heroInfoArr
this.heroInfoArr.push(res.data.data)
4·在发送英雄详情axios之前,for循环遍历heroInfoArr,判断id是否存在,存在则return,不再执行axios请求
for (let i = 0; i < this.heroInfoArr.length; i++) { if (this.heroInfoArr[i].id == id) { this.heroInfo = this.heroInfoArr[i]; return } }
9·加入iScroll滚动条插件
1·添加div包裹ul>li 并把ul的list类名给div
2·添加变量myIscroll,并在mounted中实例化iScroll,保存到变量myIscroll中
3· div添加ref属性, 并在iScroll实例中通过$refs选择div ,并配置鼠标滚轮与滚动条
5·简单计算属性购物车
1· 准备假数据
2·li列表循环遍历,渲染物品名称 name
3·准备加减 button按钮 与input数量框
<button @click='reduce(index)'>-</button><input type=\"text\" v-model='item.num'><button @click='item.num++'>+</button>
注册事件与v-model绑定数据
button减物品方法
reduce(index) { if (this.list[index].num > 0) { this.list[index].num-- } }
4·在computed 使用计算属性处理数据
1·创建变量保存总价
let _price = 0; //保存总价
2·遍历li数组将每一项的数量num与价格price相乘,并保存到总价
this.list.forEach(item => { _price += item.num * item.price; })
3·计算属性返回总价
return _price
4·使用插值语法将计算属性 渲染到总价
<p>总价:{{ getResult }}</p>
5· 注意return要写在forEach之外
6·音乐播放器
项目步骤,不够完美
1·项目初始化
1·创建脚手架
vue create musciplay
2·拷贝静态资源到assets文件夹
3·启动项目
npm run serve
打开8080端口查看是否正常
4·复制基本HTML到App.vue
注意img的src图片地址
2· 音乐列表组件musicList.app
1·在components文件加中新建musicList.vue子组件
2·抽离基本HTML ,导入App.vue 并注册
import musicList from \"./components/musicList\";
3· 下载axios 并在main.js导入全局使用
import axios from 'axios'
Vue.prototype.$axios = axios //全局引入axios 使用:this.$aixos
4·进入页面就发送axios ,所以在created中发送请求
5· 在data中声明变量,并保存服务器返回的音乐数据,并渲染到页面
this.musicList=res.data.result.songs
<ul class=\"song_list\"> <li v-for=\
6· 添加iscroll插件
1·安装iscroll插件
npm i iscroll
import iscroll from 'iscroll'
3·布局
给song_wrapper类名添加定位与去掉滚动条
3层结构
4·在mounted生命钩子函数中实例化iscroll,创建变量保存
5·在每次发送axios请求音乐列表后刷新iscroll
this.$nextTick(()=>{ this.myiscroll.refresh(); })
7·在li音乐列表添加点击事件,并传递点击的音乐id ,稍后播放需要使用
3·App.vue 主组件
1·搜索框定义搜索事件,发送axios
2·并且在音乐列表组件musicList标签使用ref引用,获取子组件this,将获取到的音乐列表数据传递给子组件
3· 创建方法,获取音乐播放url
4· 将url绑定到audio标签中,并定义播放与暂停方法
<audio controls autoplay loop class=\"myaudio\" :src=\"musicUrl\" @play=\"playEvent\" @pause=\"pauseEvent\"></audio>
4· cover播放封动画面子组件
1·抽离html区域 导入子组件并注册,使用组件名做为标签插入指定位置
2·绑定class
:class=\"{playing:playing}\"
3·父组件通过refs访问到cover组件的this,根据音乐播放或暂停更改playing的值
5· comment评论子组件
1·抽离html 导入 组册 标签
2·主组件添加获取评论方法
3·通过ref引用,将评论数据传递给comment子组件
4·渲染
总结重点:
1·组件传值
父传子
1·在子组件标签添加ref引用
2·通过this.$refs 将数据传递
子传父
子传父 this.$parent
2·抽离组件的步骤
1·在components文件夹中新建子组件
2·将指定的HTML结构抽离,拷贝到子组件template
3·import 组件名 from 组件路径 引入子组件
4·在components对象中注册子组件
5·在指定区域使用组件名做为标签插入
3·iscroll滚动条插件使用步骤
1·npm安装 导入
2·在mounted钩子函数实例化
选择dom,配置属性
3·刷新
this.$nextTick(()=>{ this.myiscroll.refresh(); })
7·黑云音乐
1·项目搭建
1·创建指定项目文件夹
2· vue create hmmusic
创建项目
3· npm run serve
启动项目
4· 拷贝静态资源到assets文件夹
5·复制index.html的 css链接与html模版
<style>@import url(./assets/css/index.css);@import url(./assets/css/iconfont.css);</style>
2·轮播图
1· npm i element-ui -S
安装饿了么ui
2· import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css';
在main.js导入饿了么ui
3· Vue.use(ElementUI);
注册饿了么ui
4· 创建home主页组件并复制官方轮播图代码
5· 发送axios请求图片地址
6·定义变量保存数据并渲染页面
使用v-for渲染
3·路由
1· npm i vue-router
下载安装vue-router路由插件
2·import VueRouter from 'vue-router'
导入路由插件
3·Vue.use(VueRouter);
注册路由插件
4·const router = new VueRouter({ })
配置路由
6· <router-view></router-view>
在App.vue 使用路由占位符
7·tihs.$router.push('/路由地址?参数名=参数值')
路由传参
8·this$route.query.参数名
路由接收参数
4·axios
1· npm i axios
下载安装axios
2· import axios from ‘axios’
导入axiso
5·歌曲列表组件
1·songsList.vue
创建歌曲列表组件
2· 拷贝HTMl
3·配置路由
导入组件
4· search中方法跳转路由---------------------------------this.$router.push(`/songsList?searchVal=${this.inputVal}`);
App.vue input搜索框添加search事件
5· this.$route.query.searchVal
接收参数,注意这里的$route最后不带r
6· 发送axios请求获取数据并渲染
6·过滤器与小问题解决
0· 过滤器的基本使用
1· filters:{}
2· filters:{ filterAr(参数){return 123}}
定义一个过滤方法
3· {{ 参数 | 方法名}}
调用过滤方法
4· 注意 :不能用this
5· return arr.map(item=>{ //返回数组中的name 拼接成一个新数组 return item.name }).join('&')
使用map函数更方便
1·点击黑云音乐跳转首页
1·@click='goHome'
在黑云音乐标签定义点击事件
2· this.$router.push('/');
跳转路由 ‘/’ 就是首页
/ 代表根目录
2·在当前路由访问当前路由报错
1· this.$router.push(\"/\").catch(e => e)
在路由后添加catch捕捉错误
只能解决当前路由
全局解决
3·多个歌手页面渲染
创建过滤器
2· <div class=\"singer\">{{ item.artists | singer }}</div>
使用过滤器
4· 歌曲名过长自动换行渲染导致样式冲突
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
超出隐藏 字符显示...
7·歌曲播放组件
1·创建player组件,拷贝基本HTML
2· 在main.js导入组件,配置路由
3· songsList 组件播放按钮注册播放音乐事件并传递id
<span class=\"iconfont icon-play\" @click=\"playMusic(item.id)\"></span>
//播放音乐 playMusic(id){ this.$router.push(`/player?id=${id}`); }
4·player组件接收id 并发送axios请求
created(){ axios({ url:`http://183.237.67.218:3000/song/url?id=${this.$route.query.id}` }).then(res=>{ window.console.log(res); }) // window.console.log(this.$route.query.id); }
5· audio标签 绑定src
<audio class='audio' controls :src=\"musicUrl\" autoplay></audio>
autoplay 自动播放
6· 发送歌词aixios 与渲染
//歌词 axios({ url:`http://183.237.67.218:3000/lyric?id=${this.$route.query.id}` }).then(res=>{ this.lyric=res.data.lrc.lyric.split('\'); // window.console.log(this.lyric); })
保存到data变量中时第一次切割【 res.data.lrc.lyric.split('\') 】
<li class='lyric' v-for=\
v-for渲染时第二次切割 【 {{ item.split(']')[1] }} 】
7· 歌曲详情axios与渲染
//歌曲详情 axios({ url:`http://183.237.67.218:3000/song/detail?ids=${this.$route.query.id}` }).then(res=>{ this.songs=res.data.songs[0]; window.console.log(res.data.songs); })
filters:{ singer(singer){ return singer.map(item=>{ return item.name }).join('&') } }
渲染歌手使用的过滤器<span>{{ songs.ar | singer }}</span>
<div class=\"player\" v-if=\"songs!=''\">
注意渲染之前判断songs 是否有数据
这是顶部标签
这是常见错误!!!
8·moment 插件使用
1·npm install moment
安装moment
2· formatTime(time){ return moment(time).format('HH:mm:ss') }
定义过滤器过滤时间戳
3· moment(time).format('HH:mm:ss')
moment插件自带方法 (time)为传入的时间戳
.format('时间格式')
9·评论组件
1·新建comment组件,拷贝HTML
2·导入comment组件,配置路由
import comment from './components/comment.vue'; //导入评论子组件
3·songsList组件添加双击事件,双击跳转评论路由
<div class=\"song\" v-for=\
传递id,评论axios需要
goComment(id){ this.$router.push(`/comment?id=${id}`); }
跳转评论路由并传递id方法,路由传参$router,最后带r
4·comment组件接收参数并发送aixos 与渲染
axios({ url:`http://183.237.67.218:3000/comment/music?id=${this.$route.query.id}` }).then(res=>{ this.commentList=res.data.comments; window.console.log(res); })
发送axiso与接收参数
接收参数$route,最后不带r
filters:{ commentTime(time){ return moment(time).format('YYYY-MM-DD HH:mm') }
过滤器与时间moment插件
moment(传入时间戳).format('时间格式')
10·视频组件
1·创建视频组件,拷贝基本HTMl,导入与配置路由
import mv from './components/mv.vue'; //导入mv子组件
2· songsList组件添加mv点击事件,传递mvid并跳转路由
<span class=\"iconfont icon-editmedia\" v-if='item.mvid!=\"\"' @click='goMv(item.mvid)'></span>
//mv goMv(mvId){ this.$router.push(`/mv?mvid=${mvId}`); }
3·mv组件接收参数,发送aixos,获取数据并渲染
axios({ url:`http://183.237.67.218:3000/mv/detail?mvid=${this.$route.query.mvid}` }).then(res=>{ // 遍历url对象 找出最大的key值 let _val=0; for(let key in res.data.data.brs){ if(key>_val){ _val=key; } } this.mvUrl=res.data.data.brs[_val]; this.mvInfo=res.data.data; })
mvUrl存的是2个对象,需要遍历对象找出最大的key值
这一段代码的作用是比较对象最大的键,然后使用该键取值
11·监听器watch监视路由变化并发送axiso
watch: { \"$route.query.searchVal\
1·在songsList组件添加watch监视器,监视路由地址后的请求参数变化
2·在监听的对象方法中重新发送axios请求音乐列表
12·路由抽取
1·在src下新建router文件夹
2·新建index.js
3·输出router
3·导包:在index.js导入vue-router
import VueRouter from 'vue-router'
4·注册:
1·导入Vue
import Vue from 'vue'
2·注册到Vue.use
Vue.use(VueRoter)
5·实例化router
const router=new VueRoter({ })
6·复制组件与路由配置与子组件
注意此处子组件的路径
7·在main.js 导入index.js
import router from './router/index.js'
13·总结
1·项目搭建的基本步骤
1·在指定的文件夹运行终端命令 vue create 项目名
2·启动项目 npm run serve
3·拷贝静态资源
注意拷贝之后的图片路径与css路径
4·子组件创建
1·所有的子组件都创建在components文件夹中 以.vue为后缀
2·创建子组件后要拷贝对应的HTML
3·在main.js文件中 导入子组件
4·配置组件路由
5·路由配置
1·在src目录下创建router文件夹
2·将路由使用与子组件配置,子组件导入都放到index.js中
3·最后在main.js 导入index.js
2·路由
传递:this.$router.push('/路由路径?参数名=参数值')
带r
接收:this.$route.query.参数名
不带r
路由基本使用
1·下载
npm i vue-router
2·导入
import VueRouter from 'vue-router';
3·实例化
const router = new VueRouter({ routes:[{//在这里写路由配置}] })
4·路由配置
5·在vue实例中注入路由实例
6·在App.vue添加路由占位符
<router-view></router-view>
3·过滤器
1·过滤器都定义在 filters:{} 对象中
2·过滤器本质上是一个方法,把需要筛选的数据传入这个方法,得到想要的数据
3·配合map()方法使用
4·用到的语法
1·模版字符串
` `
2· map()
传入数组,返回数组中指定的属性
3·split()
字符串切割
4·join()
将数组转成字符串
5·$router.push()
路由传递参数
6·$route.query.参数名
7·for in 对象
使用最大的键名取对应的值
获取高清度最高的mvUrl
Vue进阶
router路由相关
1·路由列表routes是一个数组,里面每个路由配置都是一个对象
routes:[ { path:路径,component:组件名} ]
2·路由的懒加载写法
component: () => import('@/views/argu.vue')
3·嵌套路由
在路由配置对象中,使用children数组保存嵌套路由配置对象
children: [ { } ]
子级路由不需要添加' /'
4·命名路由
1·在路由配置对象中,使用name属性为路由命名,这个命名是唯一的,跳转时可以调用这个名称
2·在路由出口处使用v-bind绑定nam属性为对应的路由命名
<router-link :to=\"{ name: 'Home'}\">About</router-link>
5·命名视图
在同个页面渲染多个视图
导入
注意这里的components是带s的,说明要导入多个组件
渲染
<router-view /> <router-view name=\"email\"></router-view> <router-view name=\"tel\"></router-view>
使用name做为标识,渲染对应的导入的组件
如果没有name属性,则渲染默认的组件
当组件中没有任何内容时,可以写成但标签<router-view />的形式
6·动态路由参数
this.route.params.name
在路由页上获取动态参数
最后的参数名必须与配置时的参数名一致
在页面上使用{{ $route.params.name }} 渲染参数
7·路由重定向
使用redirect属性配置要重新定向的路径 将要跳转到main路径的请求定向到/路径
// 方法1:直接写路径
redirect: { name: 'Home' }
方法2:命名路由
redirect: to => '/'
方法3:传入一方法 ,当需要判断某些逻辑或参数时就可以使用这种方法
8·路由别名
使用alias属性为路由添加别名 当用户访问这个别名testAlias路径时访问的也是这个alias组件
9· 路由组件传参:
1·布尔模式 ,适用在动态路由匹配中,在路由配置中 添加 props=true 组件上也需要添加对应的参数名接收 props:{ name:{ type:定义数据类型, default:默认参数}}
// 允许使用路由router对象中的params做为组件的属性参数传递 传递到组件上props对象中对应的属性上
{{ name }} 将参数渲染到页面
<!-- 为了解藕将 name 做为一个参数传递 -->
2·对象模式 ,适用没有动态参数的路由, 在路由配置 添加props={ 参数名: 参数值} 同样组件上也需要对应的参数名接收 props:{ food:{ type:定义数据类型, default:默认参数}}
// 定义传递给组件上的参数对象 组件上也要有对应的food属性接收这个参数
组件中定义
<b>{{ food }}</b>
渲染到页面
3·函数模式 ,适用于在传入的属性中,根据当前路做一些处理逻辑,来处理当前传递的属性值
路由中配置
组件中配置
4·props:{ }属性
传递数据,例如子组件需要使用父组件的数据来渲染时,就在props定义与接收
上边例子中的food ,name 为属性名
default:如果没有传递这个参数过来,则使用默认的
10·编程式导航
this.$router 获取路由实例
this.$router.go(-1)
后退一页,参数为1的话就是前进一页
this.$router.back()
后退一页,与go(-1)相同
this.$router.push('/路径')
指定跳转到哪里
push会在浏览器的历史记录中添加当前离开的页面,使用后退功能时可以后退回当前页
this.$router.replace('/路径')
指定跳转到哪里,替换当前页
将当前页直接替换,不会留下历史记录,后退无法退回当前页
11·页面传参与接参
传参
this.$router.push('/路径',参数)
// path写法直接在路径后拼接this.$router.push(path: `/argu/${name}`)
this.$router.push( name: \"argu\
//query :参数 query: { name: \"chen\" } 使用query也可以
$router为vue的路由实例
接参
this.$route
this.$route.query.id
query相当于get请求,页面跳转的时候,可以在地址栏看到请求参数
this.$route.params.id
params相当于post请求,参数不会再地址栏中显示
$route 为当前跳转的对象
12·路由模式
更改路由模式在路由实例中 ,使用mode属性来修改
// mode: 'history'
// mode: 'hash'
默认模式
1·hash模式
会在地址栏中显示#号
2·history模式
不会显示#号
13·路由匹配不到则跳转404
// * 代表所有的路径 这个配置必须写在路由最底部 如果匹配不到对应的路由 才会展示这个404页面
// 路由优先级: 从上到下, 如果同一个路径定义了2个 但是组件是不同的 ,这是匹配的只会是第一个组件
自定义列slot-scope
<template slot-scope=\"scope\">{{ scope.row.create_time | filterTime }}</template>
slot只能写在template标签内
获取本行数据,自定义渲染的内容,例如有的数据返回的是1 /0 根据1/0来渲染不同的结果
vue状态管理
Actions
用户在界面上的动作
Mutations
提交数据状态的更改的方法
State
驱动应用的数据源,保存数据的仓库
Vue components
vue组件/视图
文件抽取
将处理不同的动作分别抽成一个单独的JS文件,再将其导入一个index.js中
1· 在src根目录下创建store文件夹,所有关于vuex仓库的文件都放在其中
2·state.js
保存数据源
const state = { 在这个对象中保存数据 }
export default state
暴露这个文件
3·Mutations.js
保存处理数据的方法
const mutations = { 在这个对象中保存处理数据的方法}
export default mutations
4· index.js
导入Vue与所有抽离的文件
import Vue from 'vue'import Vuex from 'vuex'import state from './state'import getters from './getters'import mutations from './mutations'import actions from './actions'import user from './module/user'
Vue.use(Vuex)
注册vuex
export default new Vuex.Store({ 在这个对象中注册导入的文件 })
实例化一个Vuex仓库,并导入文件
5· main.js
在main.js中引入index.js
import store from './store'
简写的方式,程序会自动匹配index.js
最后在new Vue 中挂载store
state.js
vuex的状态,可以理解为vue中的data,区别在于state中定义的值,每个组件都可以使用
根目录下访问方式
1· this.$store.state.appName
appName为属性名
2· ...mapState([ 'appName' ])
...展开操作符会展开一个state对象,mapState会将这些展开的内容返回,最后使用appName属性名来匹配,与方法 1 一致
3· ...mapState({ appName: state=>state.appName })
传入的是一个对象,与方法2类似
模块中的访问方式
1· this.$store.state.user.userName
user为模块名,用户相关的信息都保存在这个模块中
工具函数
vuex自带的函数,可以快速获取指定模块中的数据
mapState
import { mapState } from 'vuex'
mapGetters
import { mapGetters } from 'vuex'
mapMutations
import { mapMutations } from 'vuex'
mapActions
import { mapActions } from 'vuex'
getters.js
vuex中的计算属性,与vue实例中的计算属性用法一致,依赖一个值或多个值,产生一个新的值
使用方法
添加:appNameV: (state)=>{ return `state.appName ${V2.0}`}
state为数据源
将state以参数传入,就可以访问其中的数据,在将处理后的结果return出去
调用:
return this.$store.gettes.appNameV
...mapGtters([ 'appnameV' ])
mutations.js
保存处理state数据的同步方法合集的地方
state为同级的数据仓库
第二个参数为在组件中调用这个setAppName方时传递的参数,这个参数就是期望修改的值
...mapMutations([ 'setAppName' ])
平铺方法之后还要再次调用
this.setAppName('需要传递的参数') ,注意参数的传递方式
actions.js
保存处理state数据的异步方法集合的地方
添加: updateAppName( {commit} ) {}
第一个参数是一个对象:{ commit } 解构赋值,这里为mutations中的commit提交方法
调用
...mapActions([ updateAppName ])
this.$store.dispatch('updateAppName',参数)
参数添加在后面
module
模块,当项目非常庞大的时候使用,拆分数据成模块
解决跨域问题
跨域问题的产生
根据浏览器的同源策略,如果域名/端口/IP 其中一个不同,则产生跨域
解决方法
1·在vue.config.js配置文件中设置代理,无论发送的是什么请求,都会将请求代理到指定的路径
module.exports = { devServer: { proxy: 'http://localhost:3000' }}
组件化技术【组件通信/插槽】
组件通信
父子
props
父属性绑定
子props接收
$refs
引用通信
$children
子父
$emit
子派发事件通信
@eventName
谁派发谁监听事件
兄弟
$parent
父搭桥通信
$root
根组件搭桥通信
没关系
$bus
new Vue 实例通信
祖孙后代
provide
提供
inject
注入
provide实例
inject实例
内容分发slot 插槽
匿名插槽
<slot/>
<template>内容</template>
具名插槽
<slot name='指定名'>
<template v-slot:指定名>内容</template>
简写 # 必须有参数 ,具名插槽必须在template上使用
作用域插槽
<slot :foo='foo'>
<template v-slot:foo='slotProps'>
slotProps是一个对象,可以直接使用{ foo } 对象解构来获取数据 , 这里解构的是slot 中的属性名而不是值
递归组件
组件内部自己渲染自己
1·必须有结束条件
2·必须有name值
一般在树状结构的数据中使用,例如级联选择框
子主题 5
关于弹性布局【display:flex】的复习
概念:把某个元素变成容器,让这个容器来控制它包裹的元素
1·弹性属性【display:flex】设置在父元素上【弹性容器】,父元素中的子元素都是弹性盒子中的项
2·默认存在2根轴
主轴x , 默认:从左往右
侧轴y,默认:从上往下
3· 容器属性
flex-direction
【单词翻译:flex:弹性,direction:方向 ,row:行,reverse:翻转 , column:列】
决定主轴的方向,就是盒子中元素的排列方向
rou 默认值,水平从左往右
row-reverse ,翻转,水平从右往左
column ,垂直从上往下
column-reverse , 翻转,垂直从下往上
flex-wrap
决定当元素排列不下时,是否换行
nowrap 默认值,不换行
wrap ,允许换行,第一在上
wrap-reverse, 换行翻转, 第一行在下
flex-flow
flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap
justify-content
【单词翻译: justify :说明 ,content:内容,start:开始, end:结束, center:中心 , space:空间, between:在····中间, around:在···周围】
决定项目,也就是容器中的元素在主轴上的排列方式
flex-start, 在主轴开始的地方, 左对齐
flex-end , 在主轴结束的地方, 右对齐
center , 在主轴居中心的地方 ,居中
space-between , 两端对齐 ,每个项目间隔相等 自动平均分
space-around , 项目周围的间隔都相等, 左右两边自动平均
align-items
【单词翻译: align:排列,排成一行, items:项目 , baseline:基线 , stretch:伸展, 展开】
决定项目在侧轴的排列方式
flex-start, 在侧轴开始的地方对齐排列 , 上对齐
flex-end , 在侧轴结束的地方对齐排列 , 下对齐
center , 在侧轴中心的地方对齐排列 ,居中
baseline, 与文字的基线对齐
stretch , 默认值 ,如果项目/元素 未设置高度 ,则自动填充满整个弹性容器
align-content
定义多根轴线的对齐方式, 就是元素较多,换行的时的对齐方式
flex-start , 与侧轴的起点对齐
flex-end , 与侧轴的终点对齐
center , 与侧轴的中心点对齐 居中
space-between , 与侧轴两端对齐,轴线之间的间隔平均分布
space-around , 每根轴线两侧的间隔都相等
stretch ,默认值,轴线占满整个交叉轴
es6语法
forEach【遍历数组/对象】
作用:对数组进行循环遍历,与for循环相似
ruturn不能终止循环
forEach没有返回值
item:数组每一项
index:数组每一项的下标
includes 【查找数组元素/指定字符】返回boolean
1·作用:判断某个数组中是否存在某个元素,或某个字符串中是否包含某个字符,包含返回true,不包含则返回false
例如天知道:根据返回数据是否包含某个字符,显示不同的天气图标
2·与indexOf() 用法相似,比indexOf简单方便
3·注意:任何字符串中都包含 '' 空字符串,有元素或者空元素的数组[]都不包含 '' 空字符串
map 【筛选数组/对象】返回指定项
作用:遍历数组,返回指定的项,例如对象中的name成员
1·返回新数组=数组.map(item=>{ return 新数组的值})
true: 新数组.push(item)
false:继续循环
例如黑云音乐的过滤器,两个数组中筛选歌手name,并返回name
2·如果没有return 新数组就是undefined,所以注意不要忘了return
findIndex 【查找符合条件的第一个元素的下标】
使用场景:查找数组符合条件的第一项,如果没有符合条件的项,返回-1
boolean: true 返回值=index,终止循环
boolean:false 继续循环,直到结束
找到了:返回对应下标,找不到:返回-1
filter 【过滤数组/对象】
使用场景:过滤出数组中符合条件的项,并返回一个新的数组
true: 返回值.push(item)
false:不做任何操作
Object的静态方法
所谓的静态方法,是部署在Object对象自身上的方法
Object.keys(对象)
参数是一个对象,返回一个数组,返回该对象身上所有的【键名】,可枚举的属性
使用场景:
黑云音乐MV组件中快速过滤出清晰度最高的mv url
判断是否是空数组
Object.keys.length!=0
Object.values(对象)
参数是一个对象,返回一个数组,返回该对象身上所有的【键值】,可枚举的属性
如果参数是一个字符串,会返回一个各个字符串组成的数组
Object.assign(对象1,被拷贝的对象2)
把对象2合并到对象1,返回一个新的对象,并且会改变对象1
用展开运算符...更便捷
Object.entries(对象)
entries:复数形式
以二维数组的形式返回对象中的键值对,每一个数组都是一个数组
Object.entries方法的一个用处是,将对象转为真正的Map结构。
展开运算符 ...
1·函数传参中使用展开运算符
2·数组字面量中使用展开运算符
实例1
合并两个数组
实例2
解构赋值,注意展开运算符只能用于最后
实例3
将类数组转化成真正的数组
实例4
Math.max(...arr)
解构数组arr ,求出最大值
解构的意思: 把数组或对象 拆分成一个一个的元素
for of
遍历数组,快速获取符合条件的元素
paSstart(),padEnd()
字符串补全,如果某个字符串长度不够会在头部/尾部补全
一共接收2个参数, 参数1:说明字符串最小长度 参数2:不足最小长度用来补全的字符串
如果符合第1个参数的规则,则返回原字符串,如果超出规则,则会截掉超出部分的字符串
如果省略第二个参数,则默认用空格补全
new Set()
新的数据类型,这种数据类型会保证所有的数据都是唯一性的
Set不是数组
Set配合...展开符可以快速的数组去重 : new Set(arr); [...arr]
... 展开运算符
将数组或对象展开
...mapState
Todo_List
功能1:input输入框键盘事件,输入内容回车之后将内容显示在下方子组件
1·input绑定v-model保存输入内容
v-model='content'
@keyup.enter='addTodo'
// input回车后触发 使用todoData循环渲染todo-item addTodo() { // 如果input输入内容为空 直接return if (this.content === \"\
3·使用todoData数组 v-for循环渲染子组件TodoItem
4·使用属性绑定,将遍历的数组todoData传递给子组件
:todo='item'
在子组件标签上的
分支主题
props:{ todo:Object}
todo是父组件绑定的属性,Object是指定数据的类型
{{ todo.content }}
功能2:点击单选框,更改lable样式
1·准备样式类名,根据父组件传递的todo数据对象中的completed属性,如果是true就添加类名,否则不添加
<div :class=\
2·在input单选框使用v-model绑定todo.completed ,如果单选框被选中,则为true ,true则触发类名completed
<input type=\"checkbox\" class=\"ckinput\" v-model=\"todo.completed\" />
功能3:点击X删除对应的待办事项
1· button按钮绑定点击事件
<button @click=\"deleteItem\" class=\"deleteBtn\"></button>
2·在点击事件deleteItem中使用事件提交,并把要删除的item项的id传递给父组件
$emit() 提交一个事件
'del' 事件名
this.todo.id 触发这个事件传递的数据
3·在父组件的todo-item子组件标签上添加一个事件监听del,并添加处理函数,触发的事件的时候根据传递的id删除对应的数据
@del=\"handleDeleteItem\"
del监听的事件名
监听子组件提交的del事件,并接收id ,根据id来删除对应的item项
使用数组下标删除splice ,再使用数组查找下标findIndex 根据id判断找出对应的下标
功能4:子组件中统计待办事项条数的数据实时变化
1· 父组件data准备total变量,统计待办事项会根据这个值来改变,默认为0
total: 0
2·使用watch属性监视todoData数据数组的变化,数组的长度就是total的值
wathc // 监听 (这里监听是为了给total赋值)
todoData //监听的数据对象
deep:true //深度监听
handler(){ } //一开始数据没有改变是不会监听的,这个方法可以在数据未发生变化之前就开始监听
最后根据todoData中的completed属性过滤,默认值是false ,所以没有被点击完成的都会被统计为长度 ,最后得到的就是total的值,这个值会跟着todoData的length变化而变化
3·使用属性绑定,将total传递给子组件
<todo-info :total='total'></todo-info>
4·子组件使用props接收并渲染到页面上
props:{ total:Number }
功能5:当前点击的筛选【\"All\
1·在a标签筛选上上绑定点击事件,并把当前渲染的state值传递过去
@click=\"togglState(item)\"
2·事件处理函数中,将传递的item值赋给data中的state变量
togglState(state) { this.state = state; }
3·根据当前筛选项state的值来判断是否添加类名actived添加改变样式
:class=\"item===state?'actived':''\"
功能6:激活对应的筛选项,展示对应的todo事项
1·子组件在筛选项的点击事件中提交一个新的事件,给父组件传递当前激活的筛选项的值
2·父组件data中创建一个保存筛选项变化的变量
filterState: \"All\"
筛选项 过滤todo的状态,默认为所有 【有三个值:所有,已完成,未完成】
3·父组件添加事件监听,获取子组件传递的state筛选项,并保存到变量filterState中
@togglState=\"handelTogglState\"
handelTogglState(state) { this.filterState = state; }
4·使用计算属性,根据子组件传递的state筛选项,渲染不同的todoData数据
computed: { filterStateData() { switch (this.filterState) { case \"Active\": return this.todoData.filter(item => item.completed == false); case \"Completed\": return this.todoData.filter(item => item.completed == true); default: return this.todoData; } } }
// 计算属性 【这里处理过滤后要渲染的todoData数据】
filterStateData // 过滤属性名
switch (this.filterState) // 因为有3个值 使用switch来判断 filterState这个值在handelTogglState监听事件中会根据子组件传递过来的state改变而改变
功能7 :点击按钮清除所有的已完成事项
1·子组件button按钮添加点击事件
@click=\"clearCompleted\"
2·在点击事件处理函数中提交一个清除事件
clearCompleted() { this.$emit(\"clearCompleted\"); }
3·父组件监视清除事件的触发
@clearCompleted=\"handleClear\"
4·事件触发过滤掉已完成的事项
handleClear() { this.todoData = this.todoData.filter(item => item.completed == false); }
知识回顾
1·设置元素(图片与文字)的垂直对齐方式
vertical-align
baseline:默认。元素放置在父元素的基线上。
top,middle,bottom 上中下
若是与文字的基线对齐,则会撑开盒子的高度
2· 设置css样式最高权重 !important
.searchInput { width: 100px !important;}
注意⚠️:在分号之前添加
3·css渐变属性 linear-gradient
45度角方向,蓝色渐变到红色
从右下到左上,蓝色渐变到红色
4· css选择器
1·并集选择器 ,逗号
选择所有 <div> 元素和所有 <p> 元素。
2·后代选择器 空格
div p
选择 <div> 元素内部的所有 <p> 元素。
3·子代选择器 > 右尖括号
div>p
选择父元素为 <div> 元素的所有 <p> 元素。
4·属性选择器 [ ] 中括号
[target]
选择带有 target 属性所有元素。
[target=_blank]
选择 target=\"_blank\" 的所有元素。
5·a伪类选择器
a:link
选择所有未被访问的链接。
a:visited
选择所有已被访问的链接。
a:active
选择活动链接。
a:hover
选择鼠标指针位于其上的链接。
6· :nth() 伪类选择器
:nth-child(n)
注意:n是从1开始的
n可以是数字,也可以是公式,例如(1) 或(n+1)
p:nth-child(2)
\t选择属于其父元素的第二个子元素的每个 <p> 元素。
li:nth-child(n+6)
选中从第6个开始的子元素
p:nth-child(odd)
选中下标为奇数的p标签
p:nth-child(even)
选中下标为偶数的p标签
7·表单选择器
:checked
选择每个被选中的 <input> 元素。
input:checked{ background-color: #ff0000;} //为所有被选中的 input 元素设置背景色:
8·多类名选择器. 英文点 重要
.item-1.red{color: red;}
同时存在item-1 与red 两个类名的元素才被选中
5·修改鼠标cursor显示状态
cursor:default
默认
cursor:pointer
小手
6·css使元素居中方式
/* 文字水平居中 */text-align: center;
/* 文字垂直居中 */line-height: 200px
/* 盒子水平居中 */margin: auto;
/* 父盒子添加弹性,控制子元素居中 */ display: flex; justify-content: center; align-items: center;
7·css渐变
8·数组去重
let arr=new Set(oldArr); oldArr=[...arr]
set是一种新的数据类型,这种数据类型会保证每个数据都是唯一的
for( var=i;i<oldarr.lenght;i++){ if(!newarr.includes(oldarr[i])){ newarr.push(oldarr[i])}}
利用includes判断正在遍历的oldarr元素是否包含在newarr中,如果不包含则push到newarr
数据回显(待补充)
bug
cli脚手架token参数错误/js文件执行时机过早导致无法获取token的问题
问题来源
1·进入登陆页面,就执行aixos.js文件获取token方法,此时还没有登陆成功,token为nall
2·登陆成功之后,axios.js不会重新执行,所以获取不到用户信息,发送的请求都会提示token参数错误
3·重新刷新则可以正常发送请求,因为刷新页面相当于重新启动了一次项目
项目一启动,所有导入的js文件都会被执行,可以console.log() 检查, 根本原因是:只有1个html页面
只要是脚手架cli的项目,所有的js文件都是在项目一启动就会执行
函数中的代码还是在调用时才会执行
问题解决
使用axios请求拦截:只要通过axios发送的请求,都会被拦截
简单理解:在每次发送请求的请求对象的请求头中,添加一个token字段,值为获取到的token,最后将这个config请求对象return到axios实例上去
config:请求对象,每一次请求都会有的
getToken() :封装的获取token方法
intercepotrs:拦截器
elementUI表格文字居中的方法
不能写在scoped中,可以新建一个style
验证token真假
思路
1·在前置路由守卫beforeEach中添加一个请求
2·如果请求拿到的响应体代码为206,则是token错误,清除token并且导航到login
3·如果访问的不是login ,并且没有token 则导航到login
实现步骤:
1· if(to.path==='/login') next()
如果访问的是登陆页 ,放行
2·else{ if(token===null) next('/login') else{ next() }}
如果访问的不是登陆页,判断token,如果token为null ,导航到登陆页 ,否则放行
获取请求结果数据的新方法
const { data: {data}}
解构赋值
render(h) 函数
提供h函数,它可以渲染VNode(虚拟dom)
在vue框架中,是通过数据来驱动视图的,当数据改变,视图也会随着改变。这是如何做到的呢?:在数据与视图(dom)中间,还有一层虚拟dom,一旦数据发生改变,就会触发虚拟dom的比对,如果发现有不同,$mount()函数则会调用js方法处理真实的dom
$mount('#app')
dom更新
('#app') 更新目标
0 条评论
回复 删除
下一页