vue制作移动应用

文章目录

使用MUI-相当于BootStrap

  1. github下载,将dist目录放到自己项目的lib目录
  2. 导入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插件

  1. github中下载插件源码
  2. 进入目录执行npm install
    npm run build
  3. 进入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. 但是发现严格模式不支持的语法。解决方案》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;  //用于指定浏览器某个区域如何响应用户操作
}
  1. 但是tab栏不能切换了。需要刷新才能进行滑动___初始化滚动条
    将mui.js初始化代码,放在mounted声明周期函数(模板放到页面上)
    分析:刷新得时机是否正确
    类比:jquery获取dom元素前提:dom元素必须渲染到页面上
    经验:操作dom元素最好在mounted
  2. 当滑动条调试ok后,tabbar无法正常工作了,这时需要把每个tabbar按钮样式改名乘
    分析: 控制变量法,注掉某部分,查看其他是否有问题
    进入页面进行调试,发现两个class相同
    多尝试相关“区域”,
    解决:查找元素+子元素所有相关样式,复制所有相关的样式,然后改变样式名

分类列表+图片列表

  1. 获取所有分类,并渲染分类列表
  2. 使用Mint-UI组件‘lazy-load’
  3. 渲染图片列表
    按需导入,懒加载,出不来图标
##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

设置图片详情

  1. 将li改造成router-link,为了保持之间的样式不变,改造:tag:"li"渲染成li
  2. 实现详情页面布局与美化,同时渲染数据
    路由传参最好由data属性接收
    主标题:margin: 上下,左右
    子标题:display:flex justify-content:space-between 左右两端
    color font-size 字体颜色,字体大小
  3. 实现图片缩略图
    cnpm i vue-preview -S
    安装插件,类似vue-router
    循环每个图片数据,补全图片的宽和高

Vue-preview介绍
Vue-preview是一个非常好用的移动端图片预览的组件,简单易用是它的一大特点,支持滑动换图,支持手势缩放,显示当前时第几张和总共多少张。
使用步骤:

  1. 安装npm i vue-preview -S
  2. 注册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;

在手机上调试

  1. 使得电脑和手机运行在同一个网段上
  2. 在packageconfig.json配置 --host ip地址
  3. 在手机浏览器输入网址便可调试。可动态刷新

页面导航的两种方式:

  1. 标签形式 router-link
  2. 代码/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. routeparamsquerythis.router: 路由导航对象,使用JS代码,实现路由的前进,后退,跳转到URL地址

设置商品详情

本例演示在元素中的内容太大以至于无法适应指定的区域时
visible 默认值。内容不会被修剪,会呈现在元素框之外。
hidden 内容会被修剪,并且其余内容是不可见的。
scroll 内容会被修剪,但是浏览器会显示滚动条以便查看其余的内容。
auto 如果内容被修剪,则浏览器会显示滚动条以便查看其余的内容。
inherit 规定应该从父元素继承 overflow 属性的值。

  1. 抽离首页的轮播图
    轮播图组件设置props属性,谁使用此轮播图,谁就为此 子组件传递lunbotulist数据
    相当于子组件想要使用 父组件的数据
  2. 可以定义一个属性,设置父组件是否宽度自适应的
    子组件根据参数动态增加一个class,来动态控制是否增加某样式
    参数boolean值控制class
    <img :class={full : isfull}> 如果isfull为真时,增加full属性
    中间贯穿线
    注意点1: JS组件需要初始化才能用!!!查文档即可
    注意点2:只要br不生效,说明父元素启用flex布局,将子元素横着放了
    display: block设置成块元素
  3. 父组件向子组件传值
    父组件导入子组件,注册子组件,绑定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>

设置加购物车小球动画

  1. transition标签包裹小球,并设置动画生命周期函数@beforeEnter(el) @enter(el,done) @afterEnter(el)
  2. 首先position设置为absolute,通过设置固定距离调节小球位置
  3. 出现问题:a. 不同分辨率小球动画位置错误 b. 上下滑动小球动画位置错误
    解决:根据一些静态实体来动态计算需要动态变化的属性
    domObject.getBoundingRect()
    小细节:可以使用dom操作更简单,页面渲染后获取到任意元素,和组件没有关系
  4. 出现问题:goodsinfo页面获取到numberbox组件的值。涉及到子组件向父组件传值—事件调用机制
    解决:父向子传递方法,子调用方法,同时把数据当参数传递给该方法
    问题:什么时机子组件开始传值??
    分析:分析点击±传值,最后发现中间值改变就应该传值
    解决:涉及到数据的就应该用父子传值,不涉及的直接操作dom好
    字符串转整数:parseInt(字符串)
    子组件向父组件传值==父组件向子组件传方法
    4.1. 父组件绑定方法到 引用
    4.2. 子组件调用引用

设置数字选择框的最大值

现象:在购买数量最大值中,传递仓库查出的所有商品的总数,通过组件传值并不能成功设置组件最大值
分析:是因为商品列表需要查询后台,vue渲染goodsinfo_numberbox组件时
可能还没有查询
到goods信息,导致没有传递到子组件。
因为绑定的原因
我们不知道goodinfo_numberbox组件何时能获取到max值,但是肯定能获取到max值
导致goodsinfo_numberbox组件的最大值属性不能正常使用
解决:通过watch监听goodsinfo组件传递过来的max值
然后手动设置到组件的属性中

自定义checkBox组件(每一个按钮一个组件,组件属性控制多个按钮选定多个)

为了达到和淘宝App的效果一致,最终选择自定义按钮组件,类似于复选框效果

  1. 可通过单向绑定实现 复选框显示父组件的商品属性
  2. 可通过父子传值+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;

总结:

  1. 基本数据类型,都应该做成对象,可以容易根据属性名/key获取值【不能分辨相同的商品】
  2. map数据类型:适合当做容器用,进行去重啊等功能声明js对象
  3. 声明js 对象 var obj = {} obj.name=value;
  4. 声明js map对象 var map = {} obj[name] =value;

数组容器怎么删除指定对象

  1. splice()方法:适用于知道删除元素索引的情况
    array.splice(index,howmany,item1,…,itemX)
index: 规定从何处添加/删除元素
howmany: 删除的元素个数
item: 添加到数组的新元素,随意个数
  1. 最常见的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; //停止遍历
}
})

  1. 用循环中的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名称以及判断只给对应的一个添加

  1. vue通过ref获取dom元素,动态操作dom节点失败
  2. 通过动态绑定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; 
}

设定小球动画

  1. 首先画出小球,通过参数控制其显示
<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;
},
  1. 然后加上动画,使其有动画效果
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; //将小球转为隐藏
		}
  1. 动态计算转移的坐标距离
//应该根据徽标和小球的位置
            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";

加入购物车

  1. 若购物车之间有这个商品,那么只需要更新数量
  2. 如果购物车没有这个商品,那么直接把商品保存到购物车
  3. 将购物车的商品实现本地持久化存储 LocalStorage.setItem(‘car’,this.car);
  4. 刚进入网站时,通过本地存储初始化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

  1. 注意点:
    MUI的数字选择框:不能自己绑定内部的值
    只能通过文档方式,ref方式,dom方式才能获取到
    只要是数字,最好parseInt()

  2. 子组件向父组件传值
    方案一:事件调用机制 子组件调用方法将数据传递给父组件

##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>
  1. 点击删除,首先删除当前组件的商品,根据索引i(v-for)
  2. 然后删除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状态字,将商品的选中状态其展示在购物车中

  1. var map={商品id,选中状态}
  2. 循环绑定复选框
    为何在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,并配置外网

  1. 运行webpack打包项目到dist目录
  2. 将里面的文件放到tomcat指定目录
  3. 开启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>
  1. 开启外网访问
    使用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: 组件之间共享的数据

使用步骤:

  1. 安装 2. 注册 3.创建 4. 挂载
  2. 调用this.$store.state获取vuex中的数据
    注意点:推介使用mutations的方法操作vuex中的state数据:可以快速定位错误原因
  3. 调用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是本地存储,是将数据存到浏览器的方法,一般是在跨页面传递数据时使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值