尚品汇笔记
前端核心:
1、构建页面Html+CSS+… 2、接口传来数据 3、vuex接收并处理数据 4、组件接收数据渲染到页面 5、交互
1、Vue的目录分析
node_modules: 是安装node后用来存放用包管理工具下载安装的包的文件夹。
public: 一般用于存放一些静态资源文件,例如图片,视频,音频等资源文件。需要特别注意的是webpack在进行打包的时候,会将public中的所有静态资源原封不动的进行打包。
src:
asset:也是用于存放一些静态资源文件
components:公共组件,非公共放在page
App.vue:是整个项目的根组件,所有组件的后缀名均为·vue
main.js:是文件的入口文件,程序执行先从该文件开始
babel.config.js:: 配置文件(babel相关)
package.json: 项目的详细信息记录
package-lock.json: 缓存性文件(各种包的来源)
2、项目配置
2.1:项目的基本运行指令,自动打开浏览器,打包文件,自动修复
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
2.2:关闭eslint工具(不关闭严重影响,不按照eslint语法就报错)
module.exports = {
//关闭eslint
lintOnSave: false
}
2.3:2.3 src文件夹配置别名,创建jsconfig.json,用@/代替src/
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"baseUrl": "./",
"moduleResolution": "node",
"paths": {
"@/*": [
"src/*"
]
},
//文件运行后产生的
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}
}
3、注册路由
3.1:
import VueRouter from "vue-router";
import Vue from "vue";
// 引用路由文件
import routes from './routes'
// 使用路由
Vue.use(VueRouter)
// 对外包括,方便在mian.js中应用
export default new VueRouter({
routes
})
3.2 routes文件夹统一管理路由
import Home from '../pages/Home/'
const routes=
[
{
//query参数的跳转是path的路径,params的跳转参数是name
path:'/Home',
name:'/Home',
component:Home
}
]
export default routes
3.3 main.js中注册路由,一定不能忘记在Vue中注册路由
import Vue from 'vue'
import router from './router'
new Vue({
router,
render: h => h(App),
}).$mount('#app')
4、注册全局组件
在main.js中注册过的组件,在全局都是有效的,不需要在任何vue文件中引用,直接用就好
// 引入公共组件中的TypeNav
import TypeNav from './components/TypeNav.vue'
// 注册全局组件 第一个参数就是组件的名字
Vue.component("TypeNav",TypeNav)
直接全局组件TypeNav,注册过
<template>
<div id="app">
<Header/>
<TypeNav/>
<router-view/>
<Footer/>
</div>
</template>
5.重定向:
在初始化项目时,路由自动跳转到设置的路由
// 重定向
{
path: '/',
redirect: '/Home'
},
6. 二次封装axios
主要是要用到请求拦截器和响应拦截器; 请求拦截器:可以在发请求之前可以处理一些业务,配置下baseURL路径 响应拦截器:当服务器数据返回以后,可以处理一些事情
// 封装axios
import axios from "axios";
//
const requests =axios.create({
// 配置基础路径,发请求的时候,会直接带上基本路径,不需要重复书写
baseURL:'/api',
// 相应事件5s,超过则失败
timeout:5000
})
requests.interceptors.request.use((config)=>{
// config是一个非常重要的属性,包含着发送的请求头,许多信息可以写在里里面
return config
})
export default requests
在index.js文件中书写相对应的地址
import requests from "./requests";
// /api/product/getBaseCategoryList 三级菜单
export const reqgetCategoryList=()=>requests({
url:`/product/getBaseCategoryList`,
methods:'get'
})
7.代理跨域问题
3.1:先放在这里,之后来填跨域的坑 vue.config.json
module.exports = ({
// 代理跨域
devServer:{
proxy:{
'/api':{
target:'http://gmall-h5-api.atguigu.cn',
}
}
}
})
8.Mock
8.1:封装一个mockrequest的二次封装, 和之前封装的相同,不过baseURL不同,在这里封装了,在index.js中就不需要再次书写
// 封装axios
import axios from "axios";
//
const MockRequests =axios.create({
// 配置基础路径,发请求的时候,会直接带上基本路径,不需要重复书写
baseURL:'/mock',
// 相应事件5s,超过则失败
timeout:5000
})
MockRequests.interceptors.request.use((config)=>{
// config是一个非常重要的属性,包含着发送的请求头,许多信息可以写在里里面
return config
})
export default MockRequests
8.2 创建mock响应内容
在src下创建mock文件夹,创建mockServer.js,同时在文件下下创建其他的json数据文件
import Mock from "mockjs";
// 引入json文件
import banner from './banner.json'
import floor from './floor.json'
//mock数据:第一个参数请求地址、第二个参:请求数据
Mock.mock('/mock/banner',{code:200,data:banner})
Mock.mock('/mock/floor',{code:200,data:floor})
//记得要在main.js中引入一下
//import ''@/mock/mockServer
8.3 在api中发送请求,注意请求变了
import MockRequests from "./MockRequests";
// banner轮播图mock
export const reqBannerList =()=>MockRequests({
url:`/banner`,
methods:'get'
})
// floor页面 mock
export const reqFloorList =()=>MockRequests({
url:`/floor`,
methods:'get'
})
9.接口数据被分割成两个模块
9.1 可以使用v-show配合v-for一起使用,最好不用v-if,会显示报错
vue2中,v-for的优先级比v-if高,所以警告,并不影响运行 vue3中,v-if的优先级比v-for高
但是如果一起用,还是会浪费性能,所以项目还是老老实实的computed计算属性
v-for="(img,index) in item.recommendList" :key="index" v-show="index<2"
10、轮播图swiper的封装
挖坑
11、Vuex
11.1 安装vuex npm i vuex@3 注意:vueRouter和vuex
"vue": "^2.6.14",
"vue-router": "^3.6.5",
"vuex": "^3.6.2"
12.编程式导航+事件委托解决路由跳转
12.1 事件委托:
概念:
事件委托也叫事件代理,“事件代理”即是把原本需要绑定在子元素的响应事件(click keydown…)委托给
父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡。
举个例子
- 英语老师要受英语作业,老师让学习委员统一收取作业,再交给她
学习委员就充当了委托中的父元素
好处:不需要对任何的一个子元素进行单独处理,而是汇总起来批量处理,可以大量节省内存占用,减少事件注册,比如在ul上代理所有li的click事件。
<ul id="list">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
......
<li>item n</li>
</ul>
// ...... 代表中间还有未知数个 li
12.2 实现点击任何标题都可以跳转到Search页面 实现思路:
<div class="all-sort-list2" v-for="(nav) in categoryList" :key="nav.categoryId">
<div class="item bo">
<h3>
<!-- 一级菜单 -->
<a @click="goSearch" :data-categoryName='nav.categoryName' :data- categoryId1='nav.categoryId'>{{nav.categoryName}}</a>
</h3>
<div class="item-list clearfix" >
<div class="subitem" v-for="nav1 in nav.categoryChild" :key='nav1.categoryId'>
<dl class="fore">
<dt>
<!-- 二级菜单 -->
<a @click="goSearch" :data-categoryName='nav1.categoryName' :data-categoryId2='nav1.categoryId'>{{nav1.categoryName}}</a>
</dt>
<dd >
<em v-for=" nav2 in nav1.categoryChild " :key="nav2.categoryId">
<!-- 三级菜单 -->
<a @click="goSearch" :data-categoryName='nav2.categoryName' :data-categoryId3='nav2.categoryId'>{{nav2.categoryName}}</a>
</em>
</dd>
</dl>
</div>
</div>
</div>
</div>
</div>
1、需要在点击获取点击时的数据,自定义属性就登上帷幕,在event.target.dataset属性中可以获取
2、利用es6新属性,解构赋值,取出属性,判断
3、跳转路由,这个地方写的特别好,分别定义location和query,随后赋值
goSearch(event){
// 获取当前点击的数据
let element =event.target
console.log(element)
let {categoryid1,categoryid2,categoryid3,categoryname}=element.dataset
console.log(categoryid1,categoryid2,categoryid3,categoryname )
// 如果有categoryname的话那就是a标签里面的
if(categoryname){
// 创建跳转路由
let location={name:'Search'}
// 跳转参数
let query ={categoryName:categoryname}
if(categoryid1){
query.categoryid1=categoryid1
}else if(categoryid2){
query.categoryid2=categoryid2
}else if(categoryid3){
query.categoryid3=categoryid3
}
location.query=query
this.$router.push(location)
}
},
13.transition过度效果
14.父子组件通信面包屑
Vue组件间通信的几种常见方式:
- props / $emit
-
e
m
i
t
/
emit/
emit/on 全局时间总线$bus
- ref / $refs 父子
- 依赖注入(provide / inject) 祖孙子
- Vuex 全局(用的多)
这里我们用的是props/$emit子父通信
需求:点击子组件,在index页面上呈现面包屑的效果
分析:
1、绑定点击事件
2、绑定emit的事件 this.$emit('事件名',传参)
3、父组件中写自定义事件
4、渲染页面
<template>
//简化代码,方便查看
<li v-for="mark in trademarkList " :key="mark.id" @click="BrandHandler(mark)">{{mark.tmName}}</li>
<a @click="attrHandler(attr2,attr)">{{attr2}}</a>
</template>
<script>
export default {
name: 'SearchSelector'
methods:{
// 点击品牌,出现面包屑
BrandHandler(Brand){
this.$emit('BrandHandler',Brand)
},
// 属性的面包屑
attrHandler(attr2,attr){
this.$emit('attrHandler',attr2,attr.attrId)
}
}
}
</script>
//传参props or 子传父事件
< template>
<SearchSelector :attrsList='attrsList' :trademarkList='trademarkList' @BrandHandler='BrandHandler' @attrHandler='attrHandler'/>
</template>
<script>
methods:{
// 品牌的面包屑 添加props
BrandHandler(Brand){
// es6 解构
let props=`${Brand.tmId}:${Brand.tmName}`
if( this.searchParams.props.indexOf(props)==-1){
this.searchParams.props.push(props)
}
},
// 属性的面包屑同样添加props
attrHandler(attr,attrId){
let props =`${attrId}:${attr}`
if( this.searchParams.props.indexOf(props)==-1){
this.searchParams.props.push(props)
}
},
</script>
15.分页器
这里我懒了,不太像手写分页器了,用了element-ui就当是锻炼下插件能力了 14.1 安装element-ui (npm i element-ui)
14.2main.js中注册(官网有安装教程)
import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI)
new Vue({
render: h => h(App),
}).$mount('#app')
14.3 在element-ui中取分页器代码,自己改下
<div class="block page">
<el-pagination
:current-page.sync="searchParams.pageNo"
:page-size="searchParams.pageSize"
layout="prev, pager, next, jumper"
:total="searchParams.total">
</el-pagination>
</div>
16.
|