万民优选项目总结

万民优选项目

一、git

1、简易流程

  1. git status 查看状态
  2. git add . 添加
  3. git commit -m “消息” 提交
  4. git pull origin develop 拉代码 —解决冲突
  5. 解决完冲突后重复2、3
  6. git push origin HEAD:分支名(yyDevelop)提交自己的代码到远程分支
  7. 提pr,提交之前看一下自己的文件改动是否正确
  • git stash save “信息” 放在缓存区
  • git stash apply 释放缓存后,不会删掉stash 把缓存区东西和拉下来的代码进行合并,解决冲突
  • git stash pop 释放暂存后,会删掉stash
  • git push origin -d 分支名 删除远程分支

2、warning: remote HEAD refers to nonexistent ref, unable to checkout.问题解决

当我git clone ssh地址时出现warning: remote HEAD refers to nonexistent ref, unable to checkout

解决方式:

  1. 在.git文件夹Git Bash Here
  2. 查看分支 git branch -a
  3. 切换分支即可 git checkout develop

3、Merge branch ‘develop’ of e.coding.net:marchsoft/wanminyouxue/wmyx-admin into develop # Please enter a commit message to explain why this merge is necessary,

# especially if it merges an updated upstream into a topic branch. # # Lines starting with ‘#’

  1. 只需 shift + ! 输入 wq
  2. 问题的意思是:请解释为什么合并代码 shift + !(进入编辑状态) wq (保存退出)

二、vue

1、状态(报错码)

401 token值–拦截器 没有权限

500 网络不好、服务器异常(后端)

404 路径和文件名的匹配问题

2、上传图片

<template>
	 <el-upload
          ref="upload"
          class="upload-demo"
          action="/api/resource"
          :auto-upload="true"
          multiple
          :file-list="form.resourceList"
          :limit="9"
          :on-remove="handleRemove"
          :on-exceed="handleExceed"
          :http-request="handleFileSuccess"
        >
          <el-button
            slot="trigger"
            size="small"
            type="primary"
          >选取图片</el-button>
        </el-upload>
</template>
<script>
    import { compressImage } from '@/utils/compress' // 图片压缩方法
    import { upload } from '@/utils/upload.js'
    export default {
    methods: {
    // 删除图片
    handleRemove(file) {
      // console.log(file, 'file--remove')
      // console.log(this.form.resourceList, 'this.form.resourceList')
      this.form.deleteIds.push(file.id)
      for (let i = 0; i < this.form.resourceList.length; i++) {
        if (this.form.resourceList[i].uid === file.uid) {
          this.form.resourceList.splice(i, 1)
        }
      }
    },
    // 文件个数超出指定个数
    handleExceed() {
      this.$message.warning('最多选择9个图片')
    },
    // 上传图片
    handleFileSuccess(file) {
      // console.log(file, 'file')
      const config = {
        width: 100, // 压缩后图片的宽
        height: 100, // 压缩后图片的高
        quality: 0.6 // 压缩后图片的清晰度,取值0-1,值越小,所绘制出的图像越模糊
      }
      compressImage(file.file, config).then((result) => {
        // console.log(result,"11")
        // result 为压缩后二进制文件
        upload('/api/resource', result)
          .then(res => {
            this.form.resourceList.push(res.data.data)
            // console.log(this.form.resourceList, 'resourceList')
            this.$message.success('上传图片成功')
          })
          .catch((err) => {
            this.$message.error('上传图片失败')
            console.log('返回错误', err)
          })
      })
    }

  }
}
</script>
<style lang="scss" scoped>
 //解决图片上传闪动问题
::v-deep .el-upload-list__item {
  transition: none !important;
}
</style>
  1. el-upload的属性:

    • action 请求路径
    • auto-upload=“true” 自动上传
    • multiple 支持多选图片
    • file-list 获取数据
    • limit 限制最多几张图片
  2. el-upload的方法:

    • on-remove 删除图片相应方法
    • on-exceed 超过限制图片相应方法
    • http-request上传图片相应方法
  3. 上传图片的方法

    • handleRemove 删除图片 把删除的图片id放入到deleteIds数组里,找到删除图片的uid,把它从form.resourceList删除
    • handleExceed 图片超过limit设定的个数时,进行提醒“最多选择9个图片”
    • handleFileSuccess 上传图片
      • config设置了压缩的图片的宽、高、清晰度
      • 调用压缩图片方法compressImage,传入参数图片的信息file.file和压缩图片条件config
      • 产生的result是压缩后的图片文件
      • 调用上传图片的方法upload,把result作为参数传入
      • 把接口/api/resource传给的res.data.data放入form.resourceList数组里
  4. 图片上传闪动问题 加一个css样式

    ::v-deep .el-upload-list__item {
      transition: none !important;
    }
    

3、父子组件传值

  1. 父传子

    父组件:

    <template>
    	<eForm :cate-options="cateOptions" />
    </template>  
    <script>
    import eForm from './module/form'
    export default {
    	data() {
       		return {
          		cateOptions: []
        	}
      	},
        methods: {
            // 获取商品分类
            getCate() {
                this.cateOptions = [{id:1,tname:"wuwu"},{id:2,tname:"yuyu"}]
            },
      	},
        created(){
          this.getCate()
        }
    }
    </script>
    

    子组件

    <template>
    	<el-select
           v-model="form.cateId"
           placeholder="请选择"
           style="width: 120px"
        >
         <el-option
            v-for="item in cateOptions"
            :key="item.id"
            :label="item.name"
            :value="item.id"
         />
       </el-select>
    </template>
    <script>
    export default {
       props: {
        	cateOptions: {
          		type: Array,
          		required: true
        	}
      }
    }
    </script>
    
    • 父组件要传给子组件的值cateOptions,在data中声明,在子组件中赋值:<eForm :cate-options="cateOptions" />
    • 在子组件中,用props接收cateOptions。然后就可以在子组件中用cateOptions
  2. 子传父

    • $emit

      子组件

      子组件:
      
       <span>{{childValue}}</span>
      
       <!-- 定义一个子组件传值的方法 -->
      
        <input type="button" value="点击触发" @click="childClick">
      
      
       export default {
        data () {
         	return {
          	childValue: '我是子组件的数据'
      
         	}
        },
      
        methods: {
         childClick () {  
          	this.$emit('childByValue', this.childValue)
         }
      
        }
      
       }
      

      父组件

      <!-- 引入子组件 定义一个on的方法监听子组件的状态-->
      
      <child v-on:childByValue="childByValue"></child>
      
      methods: {
         childByValue: function (childValue) {
          // childValue就是子组件传过来的值
      
          this.name = childValue
      
         }
      
        }
      
      }
      
    • 父组件调用子组件的方法通过ref

      在DOM元素上使用 r e f s 可 以 迅 速 进 行 d o m 定 位 , 类 似 于 refs可以迅速进行dom定位,类似于 refsdom(“selectId”)

      使用this.$refs.paramsName能更快的获取操作子组件属性值或函数

      //子组件:
      
      methods:{
          childMethods() {
              alert("I am child's methods")
          }
      
      }
      
    //父组件: 在子组件中加上ref即可通过this.$refs.method调用
    
    <template>
    
      <div @click="parentMethod">
    
        <children ref="c1"></children>
    
      </div>
    
    </template>
    
    
    <script>
    
      import children from 'components/children/children.vue'
    
      export default {
        data(){
          return {
          }
    
        },
    
        computed: {
        },
    
        components: {      
    
          'children': children
    
        },
    
        methods:{
          parentMethod() {
            console.log(this.$refs.c1) //返回的是一个vue对象,可以看到所有添加ref属性的元素
              
            this.$refs.c1.childMethods();
    
          }
    
        },
    
        created(){
        }
    
      }
    
    </script>
    

    可以通过$parent和$children获取父子组件的参数
    我们可以使用$children[i].paramsName来获取某个子组件的属性值或函数,$children返回的是一个子组件数组

    父组件

    <template>
      <div class="parent">
        <children1></children1>
        <children2></children2>
        <button @click="getChildren()">使用$children来获取子组件的数据</button>
        <p>这是从children1获取到的数据:{{msgFromChild1}}</p>
        <p>这是从children2获取到的数据:{{msgFromChild2}}</p>
      </div>
    </template>
    
    <script>
    import children1 from "./children1.vue"
    import children2 from "./children2.vue"
    export default {
      name:"parent",
      components:{
        children1,
        children2
      },
      data(){
        return{
          msgFromChild1:"",
          msgFromChild2:""
        }
      },
      methods:{
        getChildren(){
          this.msgFromChild1=this.$children[0].childMsg//获取第一个子组件(children1)里的childMsg
          this.msgFromChild2=this.$children[1].childMsg//获取第二个子组件(children2)里的childMsg
        }
      }
    
    }
    </script>
    
    <style>
    
    </style>
    

    子组件(children1)

    <template>
      <div class="children1">
        children1
      </div>
    </template>
    
    <script>
    export default {
      name:"children1",
      data(){
        return{
          childMsg:"我是children1"
        }
      }
    }
    </script>
    
    <style>
    
    </style>
    

    子组件(children2)

    <template>
      <div class="children2">
        children2
      </div>
    </template>
    
    <script>
    export default {
      name:"children2",
      data(){
        return{
          childMsg:"我是children2"
        }
      }
    }
    </script>
    
    <style>
    
    </style>
    

    效果:

    在这里插入图片描述

    $parent

    父组件:

    <template>
      <div>
        子组件:<children/>
      </div>
    </template>
    
    <script>
    import children from "./children.vue"
    export default {
      components:{children},
      data(){
        return{
          parentMsg:"我是父组件的信息"
        }
      }
    }
    </script>
    
    <style>
    
    </style>
    

    子组件:

    <template>
      <div>
        <button @click="getParent()">通过$parent获取父组件信息</button>
        <p>{{msg}}</p>
      </div>
      
    </template>
    
    <script>
    export default {
      data(){
        return{
          msg:""
        }
      },
      methods:{
        getParent(){
          this.msg=this.$parent.parentMsg
        }
      }
    }
    </script>
    
    <style>
    
    </style>
    

    效果:

在这里插入图片描述

  • vue 全局事件(eventBus)

    (1)在main.js里:

    window.eventBus = new Vue();//注册全局事件对象

    (2)一个组件

    methods:{
        down(name){
          eventBus.$emit("eventBusName",name)
        }
    }
    

    (3)另一个组件

    eventBus.$on("eventBusName",function(data){
       console.log(data,'data00000000000000')
    })
    
  1. 兄弟间传值(用vuex)

4、Web Storage API的介绍和使用

1、介绍

web Storage为浏览器提供了方便的key value存储,是一种比cookie更加方便简洁的存储方式。

2、浏览器的本地存储技术

Web Storage有两种存储方式:

  1. sessionStorage:

    • 对于每一个访问源,都会维持一个独立的存储区域
    • 只要浏览器不关闭,这些数据都不会消失。所以这种存储叫做session存储。
    • 注意,这里的session和服务器端的session的意思是不一样的,这里的sessionStorage只是本地的存储,并不会将数据传输到服务器端。
    • sessionStorage的存储容量要比cookie得多,可以达到5MB。
  2. localStorage:

    • 和sessionStorage类似,也是用来做数据存储的,不同的是localStorage存储的数据不会随着浏览器的关闭而消失
    • 我们可以通过设置过期时间,使用javascript手动删除或者清除浏览器缓存来清除localStorage。
  3. 这两种存储方式是通过Window.sessionStorage 和 Window.localStorage来使用的。事实上我们看下Window的定义:

    interface Window extends EventTarget, AnimationFrameProvider, GlobalEventHandlers, WindowEventHandlers, WindowLocalStorage, WindowOrWorkerGlobalScope, WindowSessionStorage 
    
    • window继承 WindowLocalStorage和WindowSessionStorage ,所以我们可以直接从Window来获取sessionStorage和localStorage。
    • 对于每一个origin源来说,Window.sessionStorage 和 Window.localStorage 都会创建一个新的Storage对象,用来进行数据的读取
  4. 存储token,我们用的是localStorage,存储用户信息,我们用的是sessionStorage.

3、Web Storage相关接口
  1. window

    • 我们可以通过window获取sessionStorage和localStorage
  2. storage对象

    • interface Storage {
      
          readonly length: number;
      
          clear(): void;
      
          getItem(key: string): string | null;
      
          key(index: number): string | null;
      
          removeItem(key: string): void;
      
          setItem(key: string, value: string): void;
          [name: string]: any;
      }
      
  3. StorageEvent

    • 当storage发现变化的时候就会触发StorageEvent事件
  4. 判断Storage是否被浏览器有效的支持

    function storageAvailable(type) {
        var storage;
        try {
            storage = window[type];
            var x = '__storage_test__';
            storage.setItem(x, x);
            storage.removeItem(x);
            return true;
        }
        catch(e) {
            return e instanceof DOMException && (
                // everything except Firefox
                e.code === 22 ||
                // Firefox
                e.code === 1014 ||
                // test name field too, because code might not be present
                // everything except Firefox
                e.name === 'QuotaExceededError' ||
                // Firefox
                e.name === 'NS_ERROR_DOM_QUOTA_REACHED') &&
                // acknowledge QuotaExceededError only if there's something already stored
                (storage && storage.length !== 0);
        }
    }
    

    其中的type就是localStorage或者sessionStorage,我们通过捕获异常来判断是否存在有效的Storge对象。

    看下我们怎么使用:

    if (storageAvailable('localStorage')) {
      // Yippee! We can use localStorage awesomeness
    }
    else {
      // Too bad, no localStorage for us
    }
    
4、隐身模式
  1. 概念:隐身模式下,将不会存储浏览历史记录和Cookie等数据隐私选项。与Web Storage是不兼容的。
  2. 解决方法:
     - 隐身模式下Web Storage虽然是可用的,但是不会存储任何东西。
     - 有些浏览器会选择在浏览器关闭的时候清空之前的所有存储
  3. 我们在开发的过程中,一定要注意不同浏览器的不同处理方式
5、使用Web Storage API
  1. Storage.getItem() 访问属性
  2. Storage.setItem() 设置属性

注意Storage对象中的key value都是string类型的,即使你输入的是integer,也会被转换成为String。

下面的例子,都可以设置一个colorSetting属性:

localStorage.colorSetting = '#a4509b';
localStorage['colorSetting'] = '#a4509b';
localStorage.setItem('colorSetting', '#a4509b');

虽然三种方式都可以实现存取的功能,但是我们推荐使用Web Storage API:setItem, getItem, removeItem, key, length等。

除了对Storage中的值进行设置之外,我们还可以触发和监听StorageEvent。

先看一下StorageEvent的定义:

interface StorageEvent extends Event {
 readonly key: string | null;

 readonly newValue: string | null;

 readonly oldValue: string | null;

 readonly storageArea: Storage | null;

 readonly url: string;
}

每当Storage对象发送变化的时候,就出触发StorageEvent事件。

注意,如果是sessionStorage的变化,则不会被触发。

如果一个domain中的某个页面发生了Storage的变化,那么这个domain的其他页面都会监听到这个变化。当然,如果是其他domain的话,是监听不到这个StorageEvent的。

我们可以通过window的addEventListener方法,来添加storage事件,如下所示:

window.addEventListener('storage', function(e) {  
document.querySelector('.my-key').textContent = e.key;
document.querySelector('.my-old').textContent = e.oldValue;
document.querySelector('.my-new').textContent = e.newValue;
document.querySelector('.my-url').textContent = e.url;
document.querySelector('.my-storage').textContent = JSON.stringify(e.storageArea);
});

上面的例子中,我们从StorageEvent中获取了key,oldValue,newValue,url和Storage对象。

小程序:

  1. 获取存于storage里的数据:uni.getStorageSync('字段名字')
  2. 把数据存在storage里:uni.setStorageSync('字段名字')
  3. 清除本地缓存的数据:uni.removeStorageSync('字段名字')

5、轮播图片显示第几张

<template>
	<swiper @change="changeImg">
			<swiper-item  v-for="(item,index) in detailList.resourceList" :key="item.id">
				<urlImage :url="item.path" class="top_pic"></urlImage>
			</swiper-item>
		</swiper>
		<span class="page" v-if="detailList.resourceList.length>1">
			<custom-text slot="body" class="slot-text imgPage" :content="currentImg+1 + '/' + detailList.resourceList.length"></custom-text>
		</span>
</template>
<script>
export default {
    data() {
		return {
            detailList:{},
			currentImg: 0
		}
	},
    methods:{
        //通过id获取商品详情列表
		async getGoodsList(id){
			// 通过id获取商品详情列表
			details(id).then(res => {
				// console.log(res,"detail")
				this.detailList=res
				this.flag=true
			}).catch(err => {
				console.log('返回错误', err)
			})
		},
       //滑动图片时获取对当前图片页数
		changeImg(e) {
			this.currentImg = e.detail.current
		} 
    },
    onLoad (option) {
		//路由跳转拿到活动详情的id
		this.getGoodsList(option.goodId)
	}
}  
</script>
<style lang="scss" scoped>
    swiper{
		width: 750rpx;
		height: 560rpx;
		opacity: 1;
		.top_pic /deep/ .images{
			width: 750rpx;
			height: 560rpx;
		}
	}
	.page{
		z-index:100;
		width:100rpx;
		height:50rpx;
		line-height:50rpx;
		text-align:center;
		float:right;
		position:relative;
		right:0rpx;
		bottom:53rpx;
		background-color: rgba(28, 28, 28, 0.8);
		border-radius:20px;
		.imgPage{
			color:#e9e9e9;
			font-weight: 400;
		}
	}
</style>

显示结果:

在这里插入图片描述

三、CSS

1、换行、不换行

  • white-space:nowrap; //强制不换行
  • word-wrap: break-word; //换行

2、超出部分用引号表示

overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;

四、总结和反思

这是我第二次做项目,主要做的是后台,前台就写了一个页面(商品详情)。

1.这次的后台是基于SMPE框架写成的,使用框架有优点,也有缺点。

  • SMPE框架用的是比较方便,后台关于样式的东西不大多,用的框架直接复制粘贴,然后进行修改(主要是功能的不同)。
  • 但是也会有一点限制(比如商品价格后端传过来的价格显示出来就要除于100,传回给后端的时候乘于100,在这里的时候需要改框架)
  • 框架是层层嵌套的,除非万不得已,最好不要改框架的内容。但是如果一个功能通过其他的方法无法实现,那么就要去改框架(要懂得变通)。不是说框架必须不能改,框架就是为了方便开发使用的,但是如果影响到了实际使用,就可以进行部分的修改。
  • 使用一个框架,真的需要去熟悉一下框架里面有什么东西,比如说钩子函数,比如一些工具类,这样对于后来的开发会简便不少。我上一个项目没有用到框架,然后在这次就有这个烦恼,因为不熟悉这个框架所以踩了很多坑。
  1. 我总是想要等后端接口写好了,才能继续去写功能实现。其实这样不对,应该自己先写自己这个功能的逻辑,写假数据或者有软件可以模拟。其实只要逻辑跑通了,接口连接一下就可以了。

  2. 规范性错误:

    错误正确时的提示(风格需要保持一致,要不然用户体验感不好)
    超过三个属性需要换行。(代码规范问题)
    

    代码规范问题说大也大说小也小,但是要形成一种习惯,这是一个程序员的基本素养,同时也是方便他人看懂自己的代码、方便迭代。

  3. 与后端的交流方面不大好,这是最大的一个错误。前后端分离的项目需要后端和前端的共同合作才能更好地完成,我沟通能力不大好,有时候给后端描述不清楚我的问题。比如字段的名字、格式,比如后端代码的提交与否等问题,都需要多沟通交流才能更有效率完成任务。

  4. 虽然这次已经是第二次做项目了,但是自己的不足还有好多。学习永无止境,加油!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值