文章目录
Vue尚硅谷项目
一个模块组件的实现流程:
1.存储数据,存储于vuex
2.书写静态页面
3.拆分组件
4.获取服务器数据
5.展示数据
6.开发动态业务
1. 脚手架目录
- Public:一般放置静态资源(图片)
- Src:程序员的代码文件
- Assets:文件夹里面的资源会webpack会打包成一个模块放进js文件夹里面
- components:一般放置非路由组件(或者项目共用的组件)
- Pages:放路由组件
- App.vue 唯一的根组件
- main.js 入口文件【程序最先执行的文件】
- babel.config.js:babel配置文件
- package.json:看到项目描述、项目依赖、项目运行指令
- README.md:项目说明文件
2.src文件夹的别名的设置
设置src文件夹的别名的好处,找文件会方便一些
创建jsconfig.json文件
{
"compilerOptions": {
"baseUrl": "./",
"paths": {
"@/*": [
"src/*"
]
}
},
"exclude": [
"node_modules",
"dist"
]
}
3.路由组件的配置
a.前后台区别:
后台而言:
K即为URL地址(网络资源定位符)
V即为相应的中间件
http://localhost:8080/0607
app.get("/0607",(res,req)=>{
res.send('我是祖国的老花骨朵');
});
前端路由:
K即为URL(网络资源定位符)
V即为相应的路由组件
b.商品汇前端页面:SPA页面的核心
- 路由组件:一般是固定在那里(Home、Search、Login)
- 1.创建路由组件【一般放在views|pages文件夹】
- 2.配置路由,配置完四个路由组件router文件夹中
// 配置路由的地方
import Vue from 'vue'
import VueRouter from 'vue-router'
// 使用路由插件
Vue.use(VueRouter)
// 引入路由组建
import Home from '@/pages/Home'
import Login from '../pages/Login'
// 配置路由
export default new VueRouter({
// 配置路由
routes:[
{
path:"/home",
component:Home,
meta:{
show:true
}
},
- 非路由组件:进行页面的切换((Header 、Footer)(components文件夹中)
- 1.全局组件(main页面进行全局注册)
- 组件name属性的作用?
1.开发者工具中可以看见组件的名字
2.注册全局组件的时候,可以通过组件实例获取相应组件的名字 - 2.非全局组件
- 非路由组件使用分为几步:
- 第一步:定义
- 第二步:引入
- 第三步:注册
- 第四步:使用
- 1.全局组件(main页面进行全局注册)
c.路由组件的结构的搭建:
- 1.结构 + 样式 +图片资源
- 2.相应位置放入对应组件标签
d.路由的跳转
- 路由的跳转就两种形式:声明式导航(router-link:务必要有to属性)
编程式导航push||replace - 编程式导航更好用:因为可以书写自己的业务逻
- $router:进行编程式导航的路由跳转
- this. r o u t e r . p u s h ∣ t h i s . router.push|this. router.push∣this.router.replace
- $route:可以获取路由的信息|参数
- this.$route.path
- this.$route.params|query
- this.$route.meta
e.路由传参
- params参数:路由需要占位,程序就崩了,属于URL当中一部分?keyword
- query参数:路由不需要占位,写法类似于ajax当中query参数
小问题:
1)编程式导航路由跳转到当前路由(参数不变), 多次执行会抛出NavigationDuplicated的警告错误?
注意:编程式导航(push|replace)才会有这种情况的异常,声明式导航是没有这种问题,因为声明式导航内部已经解决这种问题。
这种异常,对于程序没有任何影响的。
为什么会出现这种现象:
由于vue-router最新版本3.5.2,引入了promise,当传递参数多次且重复,会抛出异常,因此出现上面现象,
第一种解决方案:是给push函数,传入相应的成功的回调与失败的回调
第一种解决方案可以暂时解决当前问题,但是以后再用push|replace还是会出现类似现象,因此我们需要重新写(重新配置push和replace方法)
1:重写push与replace方法
工作的时候想处理掉,不想处理对于你的程序没有任何影响
function push(){
return new Promise(resolve,reject){
}
}
d+e路由的跳转与传参
1.第一种声明式导航:为什么使用router-link组件的时候,会出现卡顿那?
router-link是一个组件:相当于VueComponent类的实例对象,一瞬间
new VueComponent很多实例(1000+),很消耗内存,因此导致卡顿。
{{ c1.categoryName }}
2.第二种编程式导航:push|replace
三级分类由于使用router-link的时候,会出现卡顿现象,因此采用编程式导航。
因为是有很多的级联,v-for循环得到的,因此在循环过程中,回调函数也会依次增加
优化:编程式导航+事件委派的冒泡原理将绑定一个回调函数,则会相应的隐射到每一个子节点
路由跳转的时候【home->search】:需要进行路由传递参数【分类的名字、一、二、三级分类的id】
this.$router.push()
{
name:'search',
query:{
categoryName:'电子书',
category2Id:4
}
}
// 三级联动路由跳转和传递参数的业务
goSearch(event) {
// alert(444)
// 问题1:如何判断点击子节点的是A标签
// 答:把子节点当中的a标签,加上自定义的属性,其余子节点是没有的(自定义属性:浏览器会将驼峰命名转换为一般的命名)
// 问题2:如何判断是几级的目录?
// 答:也是根据自定义属性加上的自身的ID值进行条件判断
// 问题3:如何获取当前的事件 答:event
// event.target :获取到的是触发事件的元素(h3,a,dt,dl)
let node = event.target;
// 节点有一个属性dataset属性,可以获取自定义属性与属性值 (这里一定要小写,不是给你说了么,浏览器会将自定义属性变为全部小写)
let { categoryname, category1id, category2id, category3id } =
node.dataset;
console.log(event);
// 当这个标签是A标签的时候才会进入判断
if (categoryname) {
/* {
name:'search',
query:{
categoryName:'电子书',
category2Id:4
} */
// 准备路由跳转的参数 设置对象
let location = { name: "search" };
let query = { categoryname: categoryname };
// 一级目录
if (category1id) {
query.category1id = category1id;
} else if (category2id) {
query.category2Id = category2id;
} else {
query.category3id = category3id;
}
// 路由跳转前要合并参数
// 1.判断路由中是否有params参数,有则进行合并
if (this.$route.params) {
// 动态的给location添加params属性
location.params = this.$route.params;
// 动态的给location添加query属性
location.query = query;
}
this.$router.push(location);
}
},
4.Vuex:
以前基础课程的时候,发请求操作如下:在组件的mounted中书写axios.get||post,获取到数据存储到组件的data当中进行使用
- mounted:模板已经变为真是DOM【只不过没有数据,显示空白】,因为ajax是异步,需要时间的。
- created:稍微好那么一丢丢(不算啥)
现在: - vuex:Vue官方提供的一个插件,插件可以管理项目共用数据。
- vuex:项目大的时候,需要有一个地方‘统一小仓库中请求数据,管理数据’即为仓库store
- Vuex核心概念:state、actions、mutations、getters、modules(三连环)
- state
- actions
- mutations
- getters
- modules
5.一级分类的背景效果
第一种解决方案:CSS hover 怎么简单怎么来
第二种解决方案:JS逻辑解决 20集尚硅谷完成三级联动动态背景颜色
6.完成动态展示2|3联动结构
最开始是通过css的display:none 和display block来进行显示和隐藏
JS方法::style="{display:currentIndex == index?‘block’:‘none’}"动态绑定样式
7.搜索模块中的三级联动与过渡动画
在home模块当中,使用了一个功能三级联动功能---->[typeNav]
在search模块当中,也使用三级联动的功能------->[typeNav]
a.TypeNav组件业务分析?
- 三级联动在home模块正常显示
- 三级联动在search一会显示、一会隐藏 —解决方案:通过一个响应式属性控制三级联动显示与隐藏
b.问题1
开发的时候的出现问题:在home模块下不应该出现显示与隐藏的效果 - 现在这个问题【三级联动:本身在search模块应该有显示与隐藏的业务】 ,但是在home模块下不应该出现显示与隐藏的业务
说白了:你需要让三级联动组件知道谁在用它。 - 通过$route让组件区分在那个模块下
以后在功的时候,如果出现某一个组件要区分当前在哪一个模块中【home、search】
c.解决办法
1.TypeNav组件添加v-show进行动态绑定
2.data方法中设置 show的初始值
3.通过$route路由信息区分
// 当鼠标移入时,全部商品分类列表进行展示
enterShow() {
if (this.$route.path != "/home") {
this.show = true;
}
},
// 当鼠标离开的时候,全部商品类别进行影藏
leaveShow() {
if (this.$route.path != "/home") {
this.show = false;
}
- 路由跳转的时候,相应的组件会把重新销毁与创建----【kepp-alive】
d.过渡效果
- 最早接触的时候:CSS3
- Vue当中也有过渡动画效果—transition内置组件完成
HTML:<transition name="sort"> 相应的节点和组件</transition>
CSS:// 过渡动画的样式
// 开始进入状态
.sort-enter {
height: 0;
}
// 结束状态
.sort-enter-to {
height: 461px;
}
// 定义动画的时间和速率
.sort-enter-active {
transition: all 0.5s linear;
}
- 注意1,在Vue当中,你可以给 (某一个节点)|(某一个组件)添加过渡动画效果
- 节点|组件务必出现v-if|v-show指令才可以使用。
e.TypeNav三级联动性能优化?
项目:home切换到search或者search切换到home,组件在频繁的向服务器发请求,获取三级联动的数据进行展示。
项目中如果频繁的向服务器发请求,很好性能的,因此咱们需要进行优化。
为什么会频繁的向服务器发请求获取三级联动的数据那?
三级联动的数据是全局组件,使用的组件中进行跳转,因为路由跳转的时候,组件会进行销毁的【home组件的created:在向vuex派发action,因此频繁的获取三级联动的数据】
只需要发一次请求,获取到三级联动的数据即可,不需要多次。
最终解决方案:在App中的moutend只会执行一次
main虽然也是执行一次,但是它不是组件,没有this,组件才有$store属性
8.合并参数
进入搜索页面的时候需要传递各种的参数,从而才能向服务器发请求获得相应的数据
1)合并参数*****
为什么需要合并参数(query|params):因为这些参数,对于search是有用的,因为search通过这些参数
向服务器发请求,需要把这些参数携带给服务器,服务器就会返回相应的用户的搜索的数据,search就可以进行展示。
1.1:开发的三级联动业务,当你点击a标签的时候,会进行路由的跳转,将产品的名字与id传递给search模块----(query)
1.2:点击搜索按钮的时候,用户输入进来的关键字,点击按钮的时候会通过params参数传递给search模块-----(params)
1.3路由跳转(home->search),两个地方,三级联动(typeNav)、Header组件(搜索按钮)
// 路由跳转前要合并参数
// 1.判断路由中是否有params参数,有则进行合并
if (this.$route.params) {
// 动态的给location添加params属性
location.params = this.$route.params;
// 动态的给location添加query属性
location.query = query;
}
this.$router.push(location);
}
9.mock数据
作用:生成随机数据,拦截 Ajax 请求:
拦截ajax请求:请求发布出去【浏览器会进行拦截:笨想,因为服务器】,只是项目当中本地自己玩耍数据。
对于项目而言:真实的接口 /api/xxxx 模拟的数据/mock/xxxx
模拟数据JSON:没有空格,最好使用格式化插件进行格式化。
注意:
mock(模拟数据)数据需要使用到mockjs模块,可以帮助我们模拟数据。
mockjs【并非mock.js mock-js】
http://mockjs.com/ 官方地址
模拟的数据一般:对象、数组
{
‘a|1-10’:‘我爱你’
}
使用步骤:
第一步:安装依赖包mockjs
第二部:在src文件夹下创建一个文件夹,文件夹mock文件夹。
第三步:准备模拟的数据
把mock数据需要的图片放置于public文件夹中!public文件夹会将相应的资源原封不动的打包到dist文件夹中
比如:listContainer中的轮播图的数据
[
{id:1,imgUrl:‘xxxxxxxxx’},
{id:2,imgUrl:‘xxxxxxxxx’},
{id:3,imgUrl:‘xxxxxxxxx’},
]
第四步:在mock文件夹中创建一个server.js文件
注意:在server.js文件当中对于banner.json||floor.json的数据没有暴露,但是可以在server模块中使用。
对于webpack当中一些模块:图片、json,不需要对外暴露,因为默认就是对外暴露。
第五步:通过mock模块模拟出数据
通过Mock.mock方法进行模拟数据
mock->servers:
// 这里使用mock模拟数据
// 1.引入mock
import Mock from 'mockjs'
// 2.把json数据引入进来 JSON数据不需要暴露
// webpack默认对外暴露:JSON 图片
import banner from './banner.json'
import floor from './floor.json'
// 3.mock数据:第一个请求数据是地址地址一定要写对 第二个参数:请求数据
Mock.mock("/mock/banner",{code:200,data:banner}) //模拟首页轮播图的数据
Mock.mock("/mock/floor",{code:200,data:floor})
第六步:回到入口main文件,引入serve.js
mock需要的数据|相关mock代码页书写完毕,关于mock当中serve.js需要执行一次,
如果不执行,和你没有书写一样的。
// 引入mockServe.js
import "@/mock/mockServe"
第七步:在API文件夹中创建mockRequest【axios实例:baseURL:‘/mock’】
专门获取模拟数据用的axios实例。
api->mockAjax(mock对应axios的二次封装)
const requests = axios.create({
// create里面可以传配置对象
// 配置对象
// 基础路径:baseURL就是给每个请求的路径上自动加上所配置的,就不用自己再去书写
baseURL: '/mock', //基础路径更改即可
// 请求超时的时间
timeout: 5000
})
api->index(// 这个文件进行统一的API管理)
//获取floor的数据/floor后台接口路径
export const reqGetFloor = ()=>mockrequest.get('/floor')
// 获取search的数据 这个函数需要不需要外部传递的参数?要给服务器带参进行params给服务器传递参数 调这个函数得有相应的参数 错错错需要接收home页传递过来的params数据和query数据/api/list
// 当前这个接口。给服务器发请求的时候,至少得是一个空对象
export const reqGetSearchInfo = (params)=>requests({
在开发项目的时候:切记,单元测试,某一个功能完毕,一定要测试是否OK
10.swiper基本的使用?
常用的场景即为轮播图----【carousel:轮播图】,swiper移动端可以使用,pc端也可以使用。
Swiper使用步骤:
- swiper安装到项目当中
- 第一步:相应组件引入依赖包【swiper.js|swiper.css】
- 第二步:静态页面中结构必须完整【container、wrap、slider】,类名不能瞎写
- (初始化swiper实例之前,页面中的节点(结构)务必要有)
- 第三步:初始化swiper实例
import Swiper from "swiper"
注意!
- home模块很多组件都使用到swiper.css,没必要在每一个组件内部都引入样式一次,
只需要在入口文件引入一次即可。
// 引入swiper样式
import "swiper/css/swiper.css"
1.初始化swiper实例在哪里书写?
- 对于Vue一个组件而言,mounted[组件挂载完毕:相应的结构不就有了吗]
mounted–>组件挂载完毕
2.动态效果为什么没有出来?
- Swiper需要获取到轮播图的节点DOM,才能给swiper轮播添加动态效果,
因为没有获取到节点。
3.第一种解决方案,延迟器(不是完美的解决方案)
created里面:created执行与mounted执行,时间差可能2ms,白扯
updated里面:如果组件有很多响应式(data),只要有一个属性值发生变化updated还会再次执行,再次初始化实例。
总结:第一种解决方案可以通过延迟器(异步)去解决问题,
但是这种解决方案存在风险(无法确定用户请求到底需要多长时间),因此没办法确定
延迟器时间。
4.Swiper在Vue项目中使用完美解决方案
-
第一种解决方案问题出现在哪里:v-for,在遍历来自于Vuex(数据:通过ajax向服务器发请求,存在异步)
-
watch:监听属性,watch可以检测到属性值的变化,当属性值发生变化的时候,可以出发一次。
-
Vuex当中的仓库数据bannerList(组件在使用):
bannerList仓库数据有没有发生过变化?
一定是有的:bannerList初始值空数组,当服务器的数据返回以后,它的bannerList存储的属性值会发生变化【变为服务器返回的数据】
组件实例在使用仓库中的bannerList,组件的这个属性bannerList一定是发生过变化,watch可以监听到。
但是直接在watch里面写也是不可以的!
原因:1.此时只是有数据,但是v-for的遍历也是需要时间的遍历数据渲染结构的(没法保证v-for的遍历完成)
组件实例的一个方法:$nextTick + watch
this.$nextTick(()=>{
})
5.nextTick官网解释:
在下次DOM更新, 循环结束之后,执行延迟回调。在 修改数据之后 立即使用这个方法,获取更新后的DOM。
作用:可以保证页面的结构是一定有的。(DOM已经全部存在)
注意:组件实例的$nextTick方法,在工作当中经常使用,经常结合第三方插件使用,获取更新后的DOM节点
11.开发Floor组件(组件之间的通信)
开发Floor组件:Floor组件它被复用的(重复使用两次)
1.Floor组件获取mock数据,发请求的action书写在哪里?
答:派发action应该是在父组件的组件挂载完毕生命周期函数中书写,因为父组件需要通知Vuex发请求,父组件获取到mock数据,通过v-for遍历 生成多个floor组件,因此达到复用作用。
2.父组件派发action,通知Vuex发请求,Home父组件获取仓库的数据,通过v-for遍历出多个Floor组件
3.v-for|v-show|v-if|这些指令可以在自定义标签(组件)的身上使用
4.为什么在Floor组件的mounted中初始化SWiper实例轮播图可以使用.
答:因为父组件的mounted发请求获取Floor组件,当父组件的mounted执行的时候。
Floor组件结构可能没有完整,但是服务器的数据回来以后Floor组件结构就一定是完成的了,因此v-for在遍历来自于服务器的数据,如果服务器的数据有了,Floor结构一定的完整的。
否则,你都看不见Floor组件
12.carousel全局组件(全局组件的拆分,父子之间的通信)
如果项目当中出现类似的功能,且重复利用,封装为全局组件----【不封装也可以】
为了封装全局的轮播图组件:让Floor与listContainer组件中的代码一样,如果一样完全可以独立出来封装为一个全局组件。
此时的floor和新的carousel全局组件也存在父子之间的组件之间的通信