文章目录
- 使用MUI-相当于BootStrap
- 用命令行方式将 修改后的代码 上传到码云
- 使用vue-devtools插件
- 制作首页APP组件
- 完成Header区域:
- 制作底部的Tabbar区域:
- 在中间区域放置一个router-view来展示路由匹配到的组件
- 制作首页轮播图布局
- 制作首页九宫格
- 制作新闻资讯列表
- 根据新闻列表链接到新闻详情
- 单独封装一个comment.vue评论子组件
- 获取所有的评论数据渲染到页面中
- 实现加载更多评论 的功能
- 发表评论
- 绘制图片列表 组件页面结构并美化样式
- 分类列表+图片列表
- 设置图片详情
- 绘制商品列表并美化页面
- 在手机上调试
- 设置商品详情
- 抽离轮播图
- 设置加购物车小球动画
- 设置数字选择框的最大值
- 自定义checkBox组件(每一个按钮一个组件,组件属性控制多个按钮选定多个)
- 自定义Radio组件(多个按钮一个组件,组件属性控制所有按钮选定一个)
- 设定小球动画
- 加入购物车
- 查询购物车所有商品
- 删除购物车商品
- 进行结算
- 每当点击开关,将最新的开关状态同步到vuex中
- 计算勾选总数和总价,因为需要动态计算,所以vuex
- 部署到tomcat,并配置外网
使用MUI-相当于BootStrap
- github下载,将dist目录放到自己项目的lib目录
- 导入MUI的样式表
import './lib/mui/css/mui.min.css'
非常好用的案例免费图标库
https://www.iconfont.cn/home/index?spm=a313x.7781069.1998910419.2
http://www.uinnova.cn/product/thingjs
用命令行方式将 修改后的代码 上传到码云
git add .
git commit -m “提交信息”
git push
使用vue-devtools插件
- github中下载插件源码
- 进入目录执行npm install
npm run build - 进入Chrom浏览器中设置,开开发者模式,点击chrom文件夹,完成
制作首页APP组件
完成Header区域:
Mint-UI的header组件
为了使得下面区域不占用header区域,通过设置body的padding,为其留下空隙
.app-container{
padding-top: 40px;
}
制作底部的Tabbar区域:
1. 显示小图标:拷贝扩展图标css样式,ttf字体文件拷贝到项目中
在中间区域放置一个router-view来展示路由匹配到的组件
1. 改造tabbar为router-link
2. 设置路由高亮:linkActiveClass:'mui-active' 覆盖默认的路由高亮的类
3. 点击tabbar中的路由链接,展示对应的路由组件
制作首页轮播图布局
1. 加载首页轮播图数据vue-resource
2. 让图片自适应宽高:设置图片的宽高
使用项目本身的图片进行测试,而不必要必须访问api获取图片
lists:[
{url:'1',img:require('../lib/imgs/timg.jpg')},
{url:'2',img:require('../lib/imgs/timg2.jpg')},
{url:'3',img:require('../lib/imgs/timg3.jpg')},
{url:'4',img:require('../lib/imgs/timg4.jpg')}
]
制作首页九宫格
设置样式:直接在页面中复制样式到项目中,做相应的修改
图片太大:固定其宽高
动画:运行流畅,帮助用户理解逻辑
制作新闻资讯列表
增加路由链接
使用MUI中的
使用vue-resource获取数据
渲染真实数据
根据新闻列表链接到新闻详情
把列表中每一项改造成router-link,同时在跳转的时候提供唯一标识
创建新闻详情组件
将路由详情地址 和组件页面对应起来
通过路由在组件之间传参
{path:'/home/newsInfo:id',component:NewsInfo},
<div class="news-container">
<ul v-for="item in information" :key="item.id">
<router-link class="mui-table-view-cell mui-media" :to="'/home/newsInfo'+item.id" tag="li">
<img class="mui-media-object mui-pull-left" :src="item.imgurl">
<h4>{{item.title}}</h4>
<div class="mui-media-body">
<span>发表时间:{{item.cdate | dataFormat}}</span>
<span>点击次数:{{item.dtimes}}</span>
</div>
</router-link>
</ul>
</div>
methods,created使用data中的数据必须使用this
methods:{
getNew(){
this.news.forEach(ele => {
if(ele.id === this.id){
this.newobject=ele;
}
});
}
},
created(){
this.getNew();
}
将URL传递过来的数据暂存到data属性中,方便以后调用
单独封装一个comment.vue评论子组件
创建一个单独的comment.vue组件模板
需要使用评论组件的页面,手动导入comment组件
在父组件中,使用components属性注册为自己的子组件
父组件引用子组件
获取所有的评论数据渲染到页面中
实现加载更多评论 的功能
加载更多按钮,绑定点击事件:请求下一页数据
点击加载更多,pageindex++,然后重新查询,并传入查询的页数
为了防止新数据 覆盖老数据的情况,获取新数据时调用数组的concat方法拼接上新数组
发表评论
把文本框做双向数据绑定
为发表按钮绑定一个事件
效验评论内容是否为空,若为空,则toast提示用户,评论内容不能为空
通过vue-resource发送请求,把评论内容提交给服务器
发post请求:url,数据对象,数据格式
当发表评论 后,刷新列表查询最新评论。但这种只会查询当前分页的数据。
解决:将页面中的评论数据手动添加到评论列表中
绘制图片列表 组件页面结构并美化样式
设置图片列表样式
.photo-list{//先保证ul左右上下无缝连接
list-style: none;
background-color:white;
margin: 0px; //组件内设置margin为0px
padding:10px; //组件内设置padding为10px
padding-bottom: 0px; //强制设置最后一张照片得padding
li{
background-color: #999;
text-align: center; //li居中显示,如果图片比较小,会显示到ul得左侧
margin-bottom: 10px; //设置图片上下间隔,导致ul多了10像素
box-shadow: 0 0 10px #999;
position: relative;
img{
width: 100%;
height: 100%;
vertical-align:middle; //消除上下标签不兼容
}
img[lazy=loading] {
width: 40px;
height: 300px;
margin: auto;
}
}
}
设置图片文字样式
.info{
position: absolute;
color: white;
text-align: left;
bottom: 0px;
background-color: rgba(117, 35, 35, 0.4);
max-height: 100px; //设置文字最大高度,超出就不显示了
.info-title{
font-size: 35px;
}
.info-body{
font-size: 15px;
}
}
- 制作顶部的滑动条
- 制作顶部的图片列表
- 需要把slider区域的mui-fullscreen类去掉:防止覆盖全屏幕
- 滑动条无法正常 触发滑动,通过检查官方文档,发现这是js组件,需要被初始化
导入mui.js
调用官方文档的方式进行初始化
mui.min.js:1697 Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
- 但是发现严格模式不支持的语法。解决方案》1. 把mui.js中的非严格模式的而代码改掉
2. 禁用webpack的严格模式禁用掉
我靠弄到1:29 2020-1-14
babel7取消严格模式
cnpm i @babel/plugin-transform-modules-commonjs @babel/plugin-transform-strict-mode -D
"plugins": [
["@babel/plugin-transform-modules-commonjs", { "strictMode": false }]
]
Unable to preventDefault inside passive event listener due to target being treated as passive.
分析
解决:
*{
touch-action:pan-y; //用于指定浏览器某个区域如何响应用户操作
}
- 但是tab栏不能切换了。需要刷新才能进行滑动___初始化滚动条
将mui.js初始化代码,放在mounted声明周期函数(模板放到页面上)
分析:刷新得时机是否正确
类比:jquery获取dom元素前提:dom元素必须渲染到页面上
经验:操作dom元素最好在mounted - 当滑动条调试ok后,tabbar无法正常工作了,这时需要把每个tabbar按钮样式改名乘
分析: 控制变量法,注掉某部分,查看其他是否有问题
进入页面进行调试,发现两个class相同
多尝试相关“区域”,
解决:查找元素+子元素所有相关样式,复制所有相关的样式,然后改变样式名
分类列表+图片列表
- 获取所有分类,并渲染分类列表
- 使用Mint-UI组件‘lazy-load’
- 渲染图片列表
按需导入,懒加载,出不来图标
##css也有层级结构
margin:0
padding:0
li充满全屏
list-style:none
去掉li的小黑点
img{
width:100%
}
图片充满全屏幕
box-shadow:0 0 0 6px #999
图片阴影
图片最大高度
max-height:80px
将字体设置到图片下边
1. 设置li为相对定位
2. 设置字体为绝对定位
3. 设置buttom为0
字体透明
background-color=rgba(0,0,0,0.4)
图片上滑上边框还能看到,设置元素堆叠层次
属性设置元素的堆叠顺序。拥有更高堆叠顺序的元素总是会处于堆叠顺序较低的元素的前面
z-index:99
设置图片详情
- 将li改造成router-link,为了保持之间的样式不变,改造:tag:"li"渲染成li
- 实现详情页面布局与美化,同时渲染数据
路由传参最好由data属性接收
主标题:margin: 上下,左右
子标题:display:flex justify-content:space-between 左右两端
color font-size 字体颜色,字体大小 - 实现图片缩略图
cnpm i vue-preview -S
安装插件,类似vue-router
循环每个图片数据,补全图片的宽和高
Vue-preview介绍
Vue-preview是一个非常好用的移动端图片预览的组件,简单易用是它的一大特点,支持滑动换图,支持手势缩放,显示当前时第几张和总共多少张。
使用步骤:
- 安装npm i vue-preview -S
- 注册import VuePreview from ‘vue-preview’;
Vue.use(VuePreview);
3.引入
vue组件中,在style设置为scoped的时候,里面在写样式对子组件是不生效的,如果想让某些样式对所以子组件都生效,可以使用 /deep/ 深度选择器。
给缩略图增加样式,可以用原图代替缩略图
.small{
/deep/ .my-gallery{ //deep深层作用选择器
display: flex;
flex-wrap:wrap;//默认换行
figure{
width: 20%;
margin: 5px;
img{
width: 100%;
box-shadow: 0 0 8px #999;
border-radius: 5px;
}
}
}
}
绘制商品列表并美化页面
默认流式布局:多张照片向下排列
display:flex(外盒子flex布局): 多张照片横向排列
flex-wrap:wrap: 让flex换行
设置每行图片张数:子盒子设置width: 50%;
问题:怎么弄图片外得盒子都显示不出solid
img{
width: 100%;
height:100%; //图片充满外盒子,把其他部门挤出去,靠
}
.goods-list{
display: flex;
flex-wrap: wrap;
.goods-item{
border: 1px solid #ccc;
width: 50%;
.old{
color:red;
}
img{
width: 100%;
}
}
}
宽度49%,border:1px solid,box-shadow
图片100%充满外div
怎样实现图片经典两列布局???
1. 设置图片两边padding
2. 设置图片两端对齐 justify-content:space-between
3. 设置字体贯穿线 text-decoration:line-through font-size font-weight
4. 图片错位:css2 父盒子 相对定位,子盒子绝对定位
css3 flex布局:设置主轴向下flex-direction:column
上下两边对齐justify-content:space-between
设置最小高度:撑一个框的位置,min-height:666px;
在手机上调试
- 使得电脑和手机运行在同一个网段上
- 在packageconfig.json配置 --host ip地址
- 在手机浏览器输入网址便可调试。可动态刷新
页面导航的两种方式:
- 标签形式 router-link
- 代码/js形式 @click=" "
router.push(’ home ') 字符串=path地址(若有参数拼接到路由里)
router.push({ path:‘home’ }) 对象=path地址(若有参数拼接到路由里)
router.push({ name:‘user’,params:{userId:123} }) 路由的名称(若有参数放到参数对象中)
注意:属性名与属性值都是id,可以仅写一个
若提供了path,则会忽略了params
this. r o u t e : 路 由 ∗ ∗ 参 数 对 象 ∗ ∗ , 所 有 路 由 中 的 参 数 p a r a m s q u e r y 都 属 于 它 t h i s . route: 路由**参数对象**,所有路由中的参数params query都属于它 this. route:路由∗∗参数对象∗∗,所有路由中的参数paramsquery都属于它this.router: 路由导航对象,使用JS代码,实现路由的前进,后退,跳转到URL地址
设置商品详情
本例演示在元素中的内容太大以至于无法适应指定的区域时
visible 默认值。内容不会被修剪,会呈现在元素框之外。
hidden 内容会被修剪,并且其余内容是不可见的。
scroll 内容会被修剪,但是浏览器会显示滚动条以便查看其余的内容。
auto 如果内容被修剪,则浏览器会显示滚动条以便查看其余的内容。
inherit 规定应该从父元素继承 overflow 属性的值。
- 抽离首页的轮播图
轮播图组件设置props属性,谁使用此轮播图,谁就为此 子组件传递lunbotulist数据
相当于子组件想要使用 父组件的数据 - 可以定义一个属性,设置父组件是否宽度自适应的
子组件根据参数动态增加一个class,来动态控制是否增加某样式
参数boolean值控制class
<img :class={full : isfull}> 如果isfull为真时,增加full属性
中间贯穿线
注意点1: JS组件需要初始化才能用!!!查文档即可
注意点2:只要br不生效,说明父元素启用flex布局,将子元素横着放了
display: block设置成块元素 - 父组件向子组件传值
父组件导入子组件,注册子组件,绑定data数据到 引用
子组件使用props属性声明引用并使用
抽离轮播图
问题:首页和商品详情,若宽度都使用100%,则不好看
<mt-swipe :auto="4000">
<mt-swipe-item v-for="item in lunbotulist" :key="item.url">
<img :src="item.img" alt="" :class="{'full':isFull}">
</mt-swipe-item>
</mt-swipe>
<style lang="scss" scoped>
.full{
width: 100%;
}
</style>
<swiper :lunbotulist="swipes" :isFull="false"></swiper>
设置加购物车小球动画
- transition标签包裹小球,并设置动画生命周期函数@beforeEnter(el) @enter(el,done) @afterEnter(el)
- 首先position设置为absolute,通过设置固定距离调节小球位置
- 出现问题:a. 不同分辨率小球动画位置错误 b. 上下滑动小球动画位置错误
解决:根据一些静态实体来动态计算需要动态变化的属性
domObject.getBoundingRect()
小细节:可以使用dom操作更简单,页面渲染后获取到任意元素,和组件没有关系 - 出现问题:goodsinfo页面获取到numberbox组件的值。涉及到子组件向父组件传值—事件调用机制
解决:父向子传递方法,子调用方法,同时把数据当参数传递给该方法
问题:什么时机子组件开始传值??
分析:分析点击±传值,最后发现中间值改变就应该传值
解决:涉及到数据的就应该用父子传值,不涉及的直接操作dom好
字符串转整数:parseInt(字符串)
子组件向父组件传值==父组件向子组件传方法
4.1. 父组件绑定方法到 引用
4.2. 子组件调用引用
设置数字选择框的最大值
现象:在购买数量最大值中,传递仓库查出的所有商品的总数,通过组件传值并不能成功设置组件最大值
分析:是因为商品列表需要查询后台,vue渲染goodsinfo_numberbox组件时,
可能还没有查询
到goods信息,导致没有传递到子组件。
因为绑定的原因
我们不知道goodinfo_numberbox组件何时能获取到max值,但是肯定能获取到max值
导致goodsinfo_numberbox组件的最大值属性不能正常使用
解决:通过watch监听goodsinfo组件传递过来的max值
然后手动设置到组件的属性中
自定义checkBox组件(每一个按钮一个组件,组件属性控制多个按钮选定多个)
为了达到和淘宝App的效果一致,最终选择自定义按钮组件,类似于复选框效果
- 可通过单向绑定实现 复选框显示父组件的商品属性
- 可通过父子传值+vuex+本地存储实现保存数据,到底选择谁合适呢??
由于非父子组件,故舍去
由于不需要跨网页保存,也不需要持久存储,而是适用于内存保存,保证速度,则应该使用vuex。
## 父组件调用按钮组件
<div class="color-container">
<div class="color-title">商品参数: </div>
<div class="color-body" v-for="color in goods.detail.color" :key="color">
<skubtn :goodsid=goods.detail.goodsId keya='color' :value=color></skubtn>
</div>
</div>
## 定义按钮组件
<div class="sku-color">
<div @click="selectSku" :class="{'checkboxa':status,'tag':true}">
<label>{{value}}</label>
</div>
</div>
export default {
data(){
return{
status:false,
sku:{} //{商品id:{key:value}}
}
},
methods:{
selectSku(){
//1. 控制复选框的状态
this.status=!this.status;
//2. 选中,则将数据保存到vuex,未选中,则将数据从vuex删除
let d={};
var k=this.keya;
var id=this.goodsid;
d[k]=this.value;
this.sku[id]=d;
//alert(JSON.stringify(this.sku));
this.$store.commit('saveSku','555');
}
},
props:['goodsid','keya','value']
}
自定义Radio组件(多个按钮一个组件,组件属性控制所有按钮选定一个)
自定义Radio中的数据结构
{id:{‘color’,红色}} //数据对象,想象做成map类型 错误决定
改进后:
{id:商品id,keya:color,value:颜色名称}
这样可以轻易的按名取值
var obj={};
obj.id=this.id;
obj.keya=this.keya;
obj.value=data;
总结:
- 基本数据类型,都应该做成对象,可以容易根据属性名/key获取值【不能分辨相同的商品】
- map数据类型:适合当做容器用,进行去重啊等功能声明js对象
- 声明js 对象 var obj = {} obj.name=value;
- 声明js map对象 var map = {} obj[name] =value;
数组容器怎么删除指定对象
- splice()方法:适用于知道删除元素索引的情况
array.splice(index,howmany,item1,…,itemX)
index: 规定从何处添加/删除元素
howmany: 删除的元素个数
item: 添加到数组的新元素,随意个数
- 最常见的ForEach循环来对比元素找到之后将其删除:
var colors = ["red", "blue", "grey"];
colors.forEach(function(item, index, arr) {
if(item == "red") {
arr.splice(index, 1);
}
});
数组容器怎么更新指定对象
遍历时候,更新数组对象,就存入了原数组 splice也影响原数组
state.car.some(item=>{
if(item.id == goodsinfo.id){
item.count +=goodsinfo.count;
return true; //停止遍历
}
})
- 用循环中的filter方法(vue不支持)
var colors = ["red", "blue", "grey"];
colors = colors.filter(function(item) {
return item != "red"
});
console.log(colors); //["blue", "grey"]
vue中使用$拼接字符串和变量无法生效
const url = https://api.github.com/search/users?q=${searchName}
符号用错了 不是引号而是与波浪符同键的点
vue怎么动态的添加class名称以及判断只给对应的一个添加
- vue通过ref获取dom元素,动态操作dom节点失败
- 通过动态绑定class属性来实现,:class={此处可以为表达式}
<div class="radio-container" v-for="(item,index) in name" :key="index">
<div @click="selectSku(index,item)" :class="{'radio-item':true,checkboxa:index==cindex}">
<label>{{item}}</label>
</div>
</div>
selectSku(index,data){
this.cindex=index;
}
设定小球动画
- 首先画出小球,通过参数控制其显示
<transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter">
<div class="bobble" v-show="flag" ref="bobbleRef"></div>
</transition>
doBobble(flag){ //首先实现小球隐藏,显示,启动动画
this.flag=!this.flag;
},
- 然后加上动画,使其有动画效果
beforeEnter(el){ //el标识js原生对象
el.style.transform = "translate(0,0)"
},
enter(el,done){ //定义进入终点
el.offsetWidth;
el.style.transform = `translate(100px,200px)`;
el.style.transition = "all 1s ease";
done(); //调用下面函数
},
afterEnter(el){
this.flag=!this.flag; //将小球转为隐藏
}
- 动态计算转移的坐标距离
//应该根据徽标和小球的位置
const ballPosition=this.$refs.bobbleRef.getBoundingClientRect();
const badgePosition=document.getElementById("myBadge").getBoundingClientRect();
// alert(JSON.stringify(badgePosition));
var xd=badgePosition.left-ballPosition.left;
var yd=badgePosition.top-ballPosition.top;
// alert(xd);
// alert(yd);
el.style.transform = `translate(${xd}px,${yd}px)`;
el.style.transition = "all 1s ease";
加入购物车
- 若购物车之间有这个商品,那么只需要更新数量
- 如果购物车没有这个商品,那么直接把商品保存到购物车
- 将购物车的商品实现本地持久化存储 LocalStorage.setItem(‘car’,this.car);
- 刚进入网站时,通过本地存储初始化vuex的state数据(防止覆盖)
注意:foreach都要遍历一边 some遍历时找到就停止了
saveToCar(state,good){
var tag=false; //默认购物车没有该商品
state.cars.some(item=>{
if(item.id == good.id && item.color == good.color && item.config == good.config){
tag=true;
item.count += good.count;
return true; //停止遍历
}
});
if(!tag){
state.cars.push(good);
}
localStorage.setItem('cars',JSON.stringify(state.cars));
alert(JSON.stringify(state.cars));
},
怎样通过本地存储初始化vuex的state数据
## 通过mutations初始化。。。。错误选择
initialVuex(state){
state.cars=localStorage.getItem('cars');
}
## 根据main.js初始化就会执行的原理
var init=JSON.parse(localStorage.getItem('cars') || '[]');
const store = new Vuex.Store({
state:{
skus:[], //保存选中多个商品的多种参数{'商品id':{color:'',config:''}}
cars:init //保存多个商品
},
}
商品的购买数量没有正确入vuex
-
注意点:
MUI的数字选择框:不能自己绑定内部的值
只能通过文档方式,ref方式,dom方式才能获取到
只要是数字,最好parseInt() -
子组件向父组件传值
方案一:事件调用机制 子组件调用方法将数据传递给父组件
##1. 父组件中编写: 子组件调用的方法,将数据传递进来
getSelectedNum(count){
this.count=count;
}
## 2. 父组件将数据传入实例属性中
data(){
return{
count:1 //存储子组件传递过来的值,默认为1
}
},
## 3.父组件绑定方法到引用上
<numbox class="numbox" @func="getSelectedNum"></numbox>
## 4. 子组件对数字组件绑定事件,将值传递给父组件
countChanged(){
this.$emit('func',parseInt(this.$refs.num.value));
}
方案二:ref获取子组件的数据
查询购物车所有商品
img标签正常显示图片,vue绑定变量就显示不出来了
<img :src="car.imgurl">
解决方案:将图片地址用require括住
detail:{
id:'564564654654',
goodsName:'华为mate30',
sell:'5000',
price:'6000',
color:['红色','黑色','白色'],
config:['8GB+64GB','16GB+128GB','32GB+256GB'],
imgurl:require('../../lib/imgs/phone02.jpg')
}
父组件car怎么将每个商品的数量传给子组件numbox
首先创建map={商品id,商品数量},此数据必须进行动态更新
错误做法,在car组件中定义:这种做法只会在刚进购物车重新计算商品数目,不会动态更新
getAllGoods(){
this.cars=this.$store.state.cars;
this.cars.forEach(item=>{
this.map[item.id]=item.count;
});
}
created(){
this.getAllGoods();
},
正确做法:在vuex中的getters中计算商品数目
//计算商品的购买数量时
getGoodsMap(state){
state.cars.forEach(item=>{
state.map[item.id]=item.count;
});
return state.map;
}
<numbox class="numbox" :nums="$store.getters.getGoodsMap[car.id]" @func="getSelectedNum"></numbox>
子组件numbox怎么将每个商品的数量传给父组件car
子组件只知道数目,而不知道是哪个商品,所以不能直接修改vuex的商品数目
解决:子组件传入商品id
props:['nums','goodsid']
<numbox class="numbox"
:goodsid="car.id"
:nums="$store.getters.getGoodsMap[car.id]"
@func="getSelectedNum"></numbox>
遇到一bug,vuex中数据正常,但是numbox展示错误 分析: 1. getGoodsMap{"2":3} 2.
获取列表技巧:methods写查询方法,data放接收参数
var idArr=[]; idArr.join(’,’)
如何从购物车本地存储中,获取商品的数量
3. 创建空对象,循环购物车数组,push('id,count)
4. o[item.id] = item.count
自动更新徽章中的商品数目
刚开始想着通过组件传参,但是 并不是父子组件关系
问题:传参主体不是父子组件关系
最终方案:通过vuex的共享存储属性
问题:App组件什么时机获取商品的总数????
解决:就在标签属性上,通过
<span class="mui-badge" id="myBadge">{{this.$store.getters.getGoodsCount}}</span>
## 错误写法
getGoodsCount(){
var sum=0;
this.cars.forEach({});
return sum;
}
## 正确写法
getGoodsCount(state){
var sum=0;
state.cars.forEach(item=>{
sum+=item.count;
});
return sum;
}
删除购物车商品
删除按钮:不能使用this关键字
<a href="#">删除{{ $store.getters.getGoodsMap[car.id]}}</a>
- 点击删除,首先删除当前组件的商品,根据索引i(v-for)
- 然后删除store中的商品,根据商品id
this.goodslist.splice( i,1); //从索引i处开始删除,删除一个
removeFormCar(state,id); //根据id删除store中的商品
进行结算
怎么通过参数控制复选框选中的状态
通过v-model双向绑定参数
<input class="btn" name="checkbox" type="checkbox" v-model="msg">
data(){
return{
msg:true;
}
}
怎么通过参数控制【v-for中多个复选框】选中的状态
根据多个商品的selected状态字,将商品的选中状态其展示在购物车中
- var map={商品id,选中状态}
- 循环绑定复选框
为何在vuex中声明,而不是在car组件中声明???
为了getters计算属性可以动态更新状态:属性中/方法中相关的数据有更改时,动态计算
const store = new Vuex.Store({
state:{
skus:[], //保存选中多个商品的多种参数{'商品id':{color:'',config:''}}
cars:init, //保存多个商品
map:{}, //{商品id:购买数量}
map2:{}, //存储{商品id:选中状态参数}
},
}
//计算商品选中状态的对应关系
getGoodsMap2(state){
state.map2.forEach(item=>{
state.map2[item.id+item.color+item.config]=item.count;
});
return state.map2;
}
// 标签直接使用
<input class="btn" name="checkbox" type="checkbox" v-model="$store.getters.getGoodsMap2[car.id+car.color+car.config]">
每当点击开关,将最新的开关状态同步到vuex中
## 注册事件
<input class="btn" name="checkbox" type="checkbox"
v-model="$store.getters.getGoodsMap2[car.id+car.color+car.config]"
@click="doCheckBox(car)">
## 更新vuex中商品的选中状态
doCheckBox(car){
this.$store.commit('updateGoodsSelected',car);
}
updateGoodsSelected(state,obj){
state.cars.forEach(item=>{
if(item.id==obj.id && item.color==obj.color && item.config==obj.config){
item.selected=!item.selected;
}
});
// alert(JSON.stringify(state.cars))
localStorage.setItem('cars',JSON.stringify(state.cars));
}
计算勾选总数和总价,因为需要动态计算,所以vuex
//计算选中商品总价和个数
selectedGoodsSum(state){
var settle={
sum:0,
totalPrice:0,
goods:[]
};
state.cars.forEach(item=>{
if(item.selected){
settle.sum+=1;
settle.totalPrice+=(parseInt(item.sell)*parseInt(item.count));
settle.goods.push(item);
}
})
// alert(JSON.stringify(state.cars));
return settle;
}
<div class="mui-card-content-inner buy">
<div class="buy-left">
<div buy-title>
总计(不含运费)
</div>
<br>
<div buy-body>
已勾选商品{{$store.getters.selectedGoodsSum.sum}}件,总价¥ {{$store.getters.selectedGoodsSum.totalPrice}}
</div>
</div>
<mt-button class="order-class" type=danger>去结算</mt-button>
</div>
部署到tomcat,并配置外网
- 运行webpack打包项目到dist目录
- 将里面的文件放到tomcat指定目录
- 开启apache的gzip压缩:打开httpd.conf
#LoadModule deflate_module modules/mod_deflate.so
#LoadModule header_module modules/mod_headers.so
在最后添加配置项:
<ifModule deflate_module>
##像一个开关,告诉apache对传输到浏览器的内容进行压缩
SetOutputFilter DEFLATE ##哪些文件启用
DeflateCompressionLevel 9 ##压缩级别1-9,递增
<ifModule>
- 开启外网访问
使用ngrok将本机映射为一个外网的服务器
import comment from './comment.vue'
## 普通路由链接
<router-link to="/home/newinfo">
</router-link>
## 传参路由,加:后面的字符串当变量来取值
<router-link to="‘/home/newinfo’+item.id">
</router-link>
## vue-router使用参数
{path:'/home/newinfo/':id,components:newinfo }
babel介绍:
旧语法:定义类—function Animal(name){ this.name=name; }
Es6语法:1. clss Animal{ static info={name:‘zx’},age:‘20’ } //与java完全类似,借鉴后端语法
2. var p1 = new Person() p1.name=‘liqi’;
支持静态属性
webpack默认只能处理一部分Es6语法,其他如果需要处理就需要其他loader处理这些语法
Babel可以将高级语法 转换为 低级语法
使用Babel
- cnpm i babel-core babel-loader babel-plugin-transform-runtime -D
- cnpm i babel-preset-env babel-preset-stage-0 -D
- 打开webpack配置文件,在module节点得rules数组中,添加匹配规则:
- {test:/.js$/,use:‘babel-loader’,exclude:/node_modules/}(不转换人已有js文件)
- 新建.babelrc得配置文件:
{
"presets": [ //预设babel得语法
"@babel/preset-env"
],
"plugins": [ //安装得插件
"@babel/plugin-transform-runtime",
"@babel/plugin-proposal-class-properties"
]
}
babel是一种js语法编译器,在前端开发过程中,由于浏览器的版本和兼容性问题,很多js的新方法和特性的使用都受到了限制。使用babel可以将代码中js代码编译成兼容绝大多数主流浏览器的代码。
mui.min.js:1697 Uncaught TypeError: ‘caller’, ‘callee’, and ‘arguments’ properties may not be accessed on strict mode functions or the arguments objects for calls to them
使用VUEX
是Vue配套的公共数据仓库,它把公共数据保存到vuex中,方便整个程序
任意组件直接获取或修改
data: 组件内私有数据
props: 父组件的数据
vuex: 组件之间共享的数据
使用步骤:
- 安装 2. 注册 3.创建 4. 挂载
- 调用this.$store.state获取vuex中的数据
注意点:推介使用mutations的方法操作vuex中的state数据:可以快速定位错误原因 - 调用buex中的方法操作state数据:
this.$store.commit(’ vuex的方法名 ') 只能传递state和某个自定义参数
this.$store.commit('saveSku','555');
const store = new Vuex.Store({
state:{
sku:[], //保存选中多个商品的多种参数{'商品id':{color:'',config:''}}
car:[]
},
mutations:{
saveSku(state,param){
alert(JSON.stringify(param));
}
},
getters:{}
})
getters属性:仅有方法属性,不能修改数据
|—类比过滤器,都没有修改数据,都是做了一层包装
|—类比computed属性,都会动态计算数据
使用情景:1. state数据不能修改,只能通过mutations的方法进行修改
2. 调用mutations的方法使用this.
s
t
o
r
e
.
c
o
m
m
i
t
(
′
v
u
e
x
的
方
法
名
′
)
3.
获
取
数
据
可
通
过
:
t
h
i
s
.
store.commit(' vuex的方法名 ') 3. 获取数据可通过:this.
store.commit(′vuex的方法名′)3.获取数据可通过:this.store.state
4. 过滤数据可通过:getters属性
获取data,props的数据都需要this对象引用
overflow属性
visible 默认值。内容不会被修剪,会呈现在元素框之外。
hidden 内容会被修剪,并且其余内容是不可见的。
scroll 内容会被修剪,但是浏览器会显示滚动条以便查看其余的内容。
auto 如果内容被修剪,则浏览器会显示滚动条以便查看其余的内容。
inherit 规定应该从父元素继承 overflow 属性的值。
align-center:center 纵向居中
vuex存储和本地存储的区别
1、实质的区别
vuex存的是状态,存储在内存,localstorage是浏览器提供的接口,让你存的是文件,以文件的形式存储在本地
2、应用场景
vuex用于组件之间的传值,localstorage则主要用于页面之间的传值
3、永久性
当刷新页面时,vuex存储的值会丢失,localstorage不会
4、总结
个人在使用的时候,觉得用localstorage可以代替vuex, 对于不变的数据确实可以,但是当两个组件共用一个数据源(对象或数组)时,如果其中一个组件改变了该数据源,希望另一个组件响应该变化时,localstorage无法做到,原因就是区别1。这俩完全就是俩个东西,vuex是vue的状态管理机制,是方便组件之间通信的。一个组件的数据变化是会映射到使用这个数据的其他的组件。而localstorage是本地存储,是将数据存到浏览器的方法,一般是在跨页面传递数据时使用。