文章目录
0. vue学习笔记之项目相关
1. 准备开始
1.1 学员反馈
mui mint 使用在什么地方啊??还有拦截器的使用,觉得脑袋空空的…没信心…
拦截器:做数据交互类似cookie的应用,不局限于浏览器,在拦截器请求发起之前加上自定义的头,
如果A页面需要加载数据显示或隐藏loadding图标 B页面也需要,C页面也需要
拦截器:在发起请求之前,显示loadding图标 在响应回来以后,隐藏loadding图标
今天吸收的不错,就是不知知道晚上跟不跟上节奏,自己做的时候会报很多错,费时间,老师我用的vscode不能写注释,能不能帮忙解决一下,不太愿意又换编辑器,换个老师就换编辑器,太麻烦,,老师辛苦了
插件
问题1: 这两个中的‘:cid’和‘title’一个是变量 一个是常量?怎么区分何时用变量何时用常量。 问题2:老师你的html是混杂模式的,但现在都写严格模式的,就像你首页轮播图样式给的max-height根本就不生效,我要写height才能显示轮播图效果,H5之后不都是严格模式的吗?你写的是H几啊?????
1.上拉加载更多再讲讲吧,不太懂 2.老师,上课前能先把飞秋上一下吗,晚上敲代码的时候出现的bug,解决一下,然后再上课 3.别忘了补充知识,上传文件3种方式 multipart/form-data
拦截器不太懂
希望老师能抽空帮我们总结一下面试的时候用来装A的话
1.2 错误解决补充
- 调试错误看报错信息
2. 今日重点
2.1 项目相关
- 图文分享
- 加载页面是时请求全部图片
- 点击标题栏 获取对应类别的图片
- 图片懒加载 mint-ui v-lazy="imf.src’
- 1.去哪里 :to="{name: ‘photo_detail’, params: {id:1}}"
- 2.导航 {name: ‘photo_detail’, path: ‘/photo/detail/:id’, component: PhotoDetail}
- 3.去了干嘛 在create函数中
- 3.1 获取路由参数 this.$route.params.id;
- 3.2 将id拼接到url上,发起后端请求
- 3.3 获取数据后将数据渲染到页面上
- 3.4 图片预览实现 vue-preview 在webpack.config.js中增加配置
{test: /vue-preview.src.*?js$/, loader: 'babel-loader'}
此时注意在图片对象中配置宽高ele.w = 500; ele.h = 400; 设置缩略图的高 - 3.5 多次使用babel-loader就需要需要多次引入options,因此可以在根目录下的.babelrc文件下配置
{"presets":["es2015"], "plugins": ["transform-runtime"]}
- 4.评论 对于大家都能使用的程序比如评论,更新数据必须从服务器获取第一页的数据才是最新的
- 4.1 首页加载获取第一页数据,赋值并显示 this.xxx = res.data.message;
- 4.2 点击加载更多,获取第二页数据并追加内容 this.xxx = this.xxx.concat(res.data.message);
- 4.3 发表评论并且获取第一页最新数据显示 this.xxx = res.data.message;
- 4.4 点击加载更多
- 4.5 输入框每次输入之后都能要清空
- 4.6 组件提供外部使用的功能 组件接收参数根据参数发起行为 props接收参数
- 4.7 抽取评论相关的组件 ==> 子组件 注册全局组件 把组件中所有相关的变量都放在data的return对象中去,所有函数放在methods中去,所有需要在crated钩子函数中放置的事件也放在应的created中,所有css样式也拿过来 变化的可以传参props:[‘cid’] 传递的话
<comment :cid="pid"></comment>
- 5 加入全局方式的loading ==> 拦截器
- 5.1 当请求发起前就显示loading,当请求响应后隐藏loading
- 5.2
Axios.interceptors.request.use(function(config){ Mint.Indicator.open({ text: 'loading...',spinnerType: 'fading-circle'});return config})
- 5.3
Axios.interceptors.response.use(function(config){ Mint.Indicator.close(); return config})
- 6 商品列表
- 6.1 上拉加载更多 父盒子和子盒子重叠的时候,就触发开始上拉的过程,当拉到一定距离的时候,才触发上拉函数
- 6.2 手动添加上拉完毕的通知
this.refs.loadmore.onBottomLoaded()
- 6.3 判断是否还有数据
if(res.data.message.length !== 10) this.allLoaded = true;
禁止调用上拉函数 - 7 商品详情
2.2 同异步文件上传
- 三种上传方式
- 同步上传 在form中增加属性 enctype=“multipart/form-data” action="/upload" method=“post”
- 异步上传文件 原生js
document.querySelector('form').onsubmit = function(e){
e.preventDefault(); //阻止表单默认行为 (return false)
var formData = new FormData();
//myFile是表单中的name属性 第二个对象是文件的数 据对象
formData.append("myFile", document.getElementById('file').files[0]);
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
console.log("OK!");
}else{
console.log(xhr.status);
}
}
xhr.open("post", '/upload');
xhr.send(formData);
}
- jQuery方式
${'form'}.on('submit',function(e){
e.preventDefault();
var formData = new FormData();
formData.append("myFile", document.getElementById('file').files[0]);
$.ajax({
type: 'post',
url: './upload',
data: formData, //必须是键值对的形式自动设置头部信息 content-type: application/x-www-form-urlencoded
contentType: false, //不需要默认的头
processData: false, //不需要转换数据
success: function(){
console.log("OK!");
}
});
})
2.3 给父元素设置高度后就能实现上拉
- vue中上拉的触发点是子盒子和父盒子底部重叠
- 子盒子拉到最低部检测加载更多
2.4 组件间的通信,加入购车和数据累加
- 非父子组件 子相父 一个vue实例来协助通信
- 数量问题,范围限制 最少为1,最多为库存
- 先创建父组件后创建子组件
created(){connect.$on("addShopCart',(num)=>{this.pickNum += num;})]}
addShopCart(){ connect.$emit("addShopCart", this.num)};
- 注意此时this指向vue实例vue$3,而不是VueComponent 此时可以用箭头函数解决
- 箭头函数最典型的应用不是为了节省代码是为了保证this
3. vue过渡动画
- vue在插入,更新或移出dom是提供多种不同的方式应用过渡效果
- 元素插入的时候 透明度从0–>1 过渡持续0.5s
- 元素移出的时候 透明度为1–>0 过渡持续0.5s
- v-enter-active: v-enter–>v-enter-to
- v-leave-active: v-leave–>v-leave-to
- 在active中可以加入动画 在enter或enter-to加入最终效果
.ball-enter-active{
animation: bounce-in .5s;
}
@keyframes bouce-in{
0%{
transform: translate3d(0,0,0);
}
50%{
transform: translate3d(140px,-50px,0);
}
75%{
transform: translate3d(160px,0,0);
}
100%{
transform: translate3d(140px,300px,0);
}
}
- 过渡效果结束后的js回调函数
v-on:before-enter/enter/after-enter/enter-cancelled
<transition name="ball" @after-enter="afterEnter">
<div> class="ball" v-if="isShow"></div>
</transition>
...
//点击时设置isShow为true
afterEnter(){
this.isShow = false;
}
4. 商品数量的CRUD和本地存储localStorage
- 购物车中追加商品
- 数组方式存储 [{id:1,num:2}] 遍历数组如果id相同就追加num,否则push一个新的记录 效率低下
- 对象方式 {x0011: 4} 如果obj[x0011]存在就追加obj[x0011] += 6; 否则新增 obj[x0011] = 6;
- 购物车中删除善品
- 思路 获取id删除该属性
-
- obj[0x11]=null;
-
- delete obj.x001/delete obj[“x001”]/obj[key]
let store = window.localStorage;
let prodTools = {};
let prods = JSON.parse(store.getItem('prods') || '{}'); //用于本地存储
prodTools.add = function(p){
if(prods[p.id]){
prods[p.id] += p.num;
}else{
prods[p.id] = p.num;
}
this.save(prods);
}
prodTools.delete(id){
delete prods[id];
this.save(prods);
}
prodTools.getProds(){
return JSON.parse(store.getItem('prods') || '{}');
}
prodTools.getTotalCount(){
let sum = 0;
for(let id in prods){
sum += prods[id];
}
return sum;
}
//存储
prodTools.save(prods){
store.setItem('prods', JSON.stringify(prods));
}
export default prodTools;
5. 商品评论功能
- 点击相应按钮触发路由的切换,路由参数
- 通过按钮的点击事件获取id,编程导航到指定路由参数
this.$router.push({name: 'goods_comment',query:{id}})
<comment :cid="$route.query.id"></comment>
6. 导航钩子实现不同from的title
- 导航钩子用于拦截导航
- 全局钩子
router.beforeEach((to, from, next)=>{})
- 某个路由独享钩子
beforeEnter:(to,from,next)=>{}
- 组件内的钩子
beforeRouteEnter/beforeRouteLeave/beforeRouteUpdate
6.1路由导航钩子
beforeRouteEnter (to, from, next) {
在渲染该组件的对应路由被 confirm 前调用
不!能!获取组件实例 `this`
因为当钩子执行前,组件实例还没被创建
不过可以创建回调给next来访问组件实例
let myTitle = '';
if(from.name === 'news.list'){
//news
myTitle = '新闻列表';
}
next(vm =>{
//通过vm访问组件实例
vm.title = myTitle;
})
},
beforeRouteUpdate (to, from, next) {
在当前路由改变,但是该组件被复用时调用
举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
导航离开该组件的对应路由时调用
可以访问组件实例 `this`
}
7.购物车新增数据
- 通过本地存储 获取商品数据 因为购物车多入口无法通过路由实现
Object.keys(obj)
获取属性后拼接字符串发起请求 - 将localStorage中的对象的num挂载到数组元素的num属性
- 在vue中添加属性是没办法做到数据响应的
- 添加属性一定要用$set来做
vm.$set(target,key,value)
this.$set(ele, 'num', prods[ele.id]);
this.$set(ele, 'isPicked', true);
//注意this指针问题
7.1 计算购物车价格 计算属性
- 1.当前商品未被勾选中不参与计算 --> 遍历数组查看被选中的情况
-
- 计算总金额等于总单价*件数,
-
- 并加上当前元素的num
7.2 删除购物车中的商品
- 1.删除localStorage
- 2.购物车小红点的num变化
- 3.删除内存
- 4.如果没有商品 就return
Object.keys(obj).length === 0
8. 每个页面的淡入淡出效果
- 在路由外边加上过渡
- mode 过渡模式 in-out/out-in
<transition name="router">
<router-view></router-view>
</transition>
<style scoped>
.router-enter-active, .router-leave-active{
transition: opacity .5s;
}
.router-enter, .router-leave-to{
opacity: .5s;
}
</style>
9. 打包使用版本号
- 文件名固定导致缓存
- 版本号可以避开缓存 一个升级全部升级
- webpack extract-text-webpack-plugin
- 在module打包css规则中使用新引入的插件
- 在插件中声明插件
- 抽取css代码css+hash
- 给js来给唯一标识
filename: '[name].[chunkhash:6].js'
- 给css来个唯一标识
new ExtractTextPlugin("style.[contenthash:6].css")
- 更新后不用重新加载,只用更改部分的
- 抽取js代码 在入口处设置多入口
- 提取webpack公共模块(内置插件)
- 压缩混淆代码
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
- mint-ui按需引入
import Header from 'mint-ui/lib/header';
import Lazyload from 'mint-ui/lib/lazyload';
Vue.component(Header.name, Header);
Vue.use(Lazyload);
//...
entry: {
main: './src/main.js',
vendors: ['vue','vue-router','moment','axios', 'vue-preview']
}
//...
plugins:[new webpack.optimize.CommonsChunkPlugin({
//manifest记录使用第三方包和依赖关系
names: ['vendors','manifest']
}),
//混淆代码
new UgifyJSPlugin()
]
- 划分目录 outpot中暴露publicPath: www.baidu.com
filename: 'js/[name].[chunkhash:6].js'
- 设置资源路径
publicPath: '/'
10.注意
- 全局的样式 要设置!important提升优先级
- 启动项目 hs -o -p 9999
10.1 分块路由懒加载
- 实现路由按需加载
const Foo = resolve => require(['./Foo.vue], resolve)