仿【得物】微信小程序实战全教程,前端framework面试题

116 阅读9分钟

结尾

学习html5、css、javascript这些基础知识,学习的渠道很多,就不多说了,例如,一些其他的优秀博客。但是本人觉得看书也很必要,可以节省很多时间,常见的javascript的书,例如:javascript的高级程序设计,是每位前端工程师必不可少的一本书,边看边用,了解js的一些基本知识,基本上很全面了,如果有时间可以读一些,js性能相关的书籍,以及设计者模式,在实践中都会用的到。

html5

开源分享:docs.qq.com/doc/DSmRnRG… <image class="ricon" style="width:26rpx;height:26rpx;" src="">

<view class="detail_bd">

立即购买

复制代码

整体分为detail_hddetail_bd两部分。自定义swiper需设置dot对应展示图片并更改样式,circular属性设置是否启用滑块切换动画,这里使用三目运算符判断是否添加新的样式类名。在定义商品价格的样式的时候可以通过first-letter伪元素来定义¥符号样式。引用组件van-goods-action使得购买按钮吸底。

05.png

<van-popup closeable position="bottom" custom-style="height: 75%">

<view class="detail_size-hd">

<view class="detail_size-hd-img">

<image bindtap="previewImage" mode="aspectFit" src="{{img.pic}}">

<view class="detail_size-hd-price">

<text style="font-size:25rpx;">¥

<text wx:if="{{activeSizeIndex==-1}}">--

<text wx:if="{{activeSizeIndex==index}}">{{item.price}}

<image src="">

<text wx:if="{{activeSizeIndex==-1}}">请选择商品

<text wx:if="{{activeSizeIndex==index}}">已选 {{item.size}}

<view class="detail_size-bd">

<van-grid square gutter="10">

<view class="size">

<text id="p3">{{item.size}}

<text id="p4">¥{{item.price}}

{{}}

复制代码

使用van-popup组件,给对应标签设置事件即可绑定弹出。例:<van-cell bind:click="showPopup"></van-cell>。三目运算符设置默认样式并且控制选中边框样式,设置closeable属性启用关闭按钮。square设置van-grid-item为方形,gutter设置格子间距。

06.png

<van-sticky sticky offset-top="{{ 180 }}">

<view class="head">

<view class="detail_produce-hd">相关推荐

<view class="detail_close" bindtap="onClose2">

<image style="width:40rpx;height:40rpx;" src="">

复制代码

设置detail_produce-hd吸顶,给右侧关闭icon绑定bind:close="onClose"事件。

获取商品详情

async onLoad(options) {  //获取对应_id的商品数据

console.log(options);

let id = options.id

console.log(id);

wx.cloud.database().collection('dewu') 

.doc(id)             

.get()

.then(res => {

console.log(res);

this.setData({

img :res.data

})

})

},

复制代码

弹出层

showPopup() {   //显示弹出层

this.setData({ 

show: true,

});

},

onClose() {     //关闭弹出层

this.setData({ 

show: false,

});

},

复制代码

选择尺码

pickSize(e) {

let flag = e.currentTarget.dataset.flag

let index = e.currentTarget.dataset.index

if(flag==index) {   

this.setData({

activeSizeIndex: -1,

flag: -1

}) 

}

else {

this.setData({

activeSizeIndex: index,

flag: index

}) 

}

},

复制代码

点击尺码,flag==index即为选中状态,再次点击时或者点击其他尺码时设置为非选中状态,否则使flag等于index,使其变成选中状态。

搜索页


002.gif

搜索页样式

01.png

<view class="page">

<view class="search">

<van-search value="{{value}}" bind:clear="onClear" placeholder="输入商品名称、货号"/>

<block wx:if="{{showHistory == true && historyList.length > 0}}">

<view class="historyContainer">

<view class="title">历史搜索<image class="delete" src="">

<view class="historyList">

<view class="historyItem">

<text class="order">{{}}

复制代码

搜索页面主要分为头部搜索框和内容(搜索推荐,历史记录和搜索到的商品列表)两部分。这里用van-sticky包装搜索框使吸顶,内容部分则用block标签包装,利用wx:if这个控制属性来判断是否显示。

搜索记录

async onSearch(e) {

// console.log(e);

if (!e.detail.trim()) {

wx.showToast({

title: '请输入商品名',

})

return

}

let {value, historyList} = this.data

if(historyList.indexOf(value) !== -1) {

historyList.splice(historyList.indexOf(value), 1)

}

historyList.unshift(value)

this.setData({

historyList

})

wx.setStorageSync('value', historyList)

let keyword = e.detail.trim()

let results = await dewuCollection

.where({

title: db.RegExp({

regexp: keyword,

options: 'i'

})

})

.get()

if (results.data.length == 0 || keyword == '') {

wx.showToast({

title: '不存在'+keyword,

})

}

else {

await dewuCollection

.where({

title: db.RegExp({

regexp: keyword,

options: 'i'

})

})

.orderBy('hot', 'desc')

.get()

.then(res => {

console.log(res);

this.setData({

results: res.data

})

})

}

},

onLoad() {

this.getSearchHistory()  //获取历史搜索

},

getSearchHistory() {

let historyList = wx.getStorageSync('value')

if(historyList) {

this.setData({

historyList

})

}

},

复制代码

页面加载时从本地storage中获取历史搜索记录,在确定搜索onSearch时判断value是否为空,将合法value插入historyList中,这里使用的时unshift方法,这样可以保证最近的搜索记录展示在前面,利用正则表达式模糊查询数据库中符合的项存入数组results中,当results.length > 0时显示商品列表。利用wx.setStorageSyncvalue存入缓存,wx.getStorageSync获取打印出来。通过indexOf方法判断value是否已经存在,是则删除historyList中的该项。

历史搜索

async historySearch(e) {

// console.log(e);

let historyList = this.data.historyList

let value = historyList[e.currentTarget.dataset.index]

this.setData({

value,               //修改value

showHotList: false,  //隐藏热门搜索

showHistory: false,  //隐藏历史搜索

results: []          //清空商品列表

})

},

复制代码

点击历史搜索项时setData使对应值改变,再调用onSearch方法。

清空控件

onClear() {

this.setData({

results: [],

value: '',

showHotList: true,

showHistory: true

});

},

onChange(e) {  //search框输入改变时实时修改数据

// console.log(e.detail);

this.setData({

value: e.detail,

showHotList: false,

showHistory: false,

results: []

})

// console.log(this.data.showHotList);

if (this.data.value=='') {

this.setData({

showHotList: true,

showHistory: true

})

}

},

复制代码

清空搜索历史

deleteSearchHistory() {

wx.showModal({

content: '确认清空历史记录',

success: (res) => {

if(res.confirm) {

this.setData({

historyList: []

})

}

}

})

wx.removeStorageSync('value')

},

复制代码

点击删除icon弹出对话框wx.showModal实现交互,用户点击确定则清空historyList并利用wx.removeStorageSync将本地存储的历史记录删除。

品牌分类页


003.gif

分类页样式

07.png

<view class="page">

<view class="search" bindtap="gotoSearch">

<van-search placeholder="搜索商品" input-align="center" disabled />

<view class="kinds">

<view class="hd">

<scroll-view class="scroll-view-left">

<view class="scroll-view-left-item {{activeNavIndex == index?'active': ''}}">

{{}}

<view class="bd">

<view class="kind-title">

<van-divider contentPosition="center">{{}}

{{}}

复制代码

分类页面主要是使用了scroll-view设置竖向滚动,点击左侧scroll-view-left-item时该项变为得物色(#00cbcc)并显示对应的品牌种类项kindsItem。整体采用flex布局,这里的坑是scroll-view-left应该把font-size设为0,在子元素scroll-view-left-item中设置font,避免块元素边距影响布局。

初始化品类

onLoad: function (options) {

this.setData({

kindNav: kindNav,

kindall: kindItem,

// console.log(this.data.kindall);

let kinds=[];

// console.log(this.data.kindall)

this.data.kindall.forEach(kind => { //循环从所有品类中获取对应kindNav的并存入数组中

if(kind.camptype == 0) {

kinds.push(kind)

}

})

this.setData({

kindItem: kinds,

})

}, )

},

复制代码

选择分类

changeKinds(e) {

console.log(e);

let {index, type} = e.currentTarget.dataset;

console.log(index, type);//index与推荐品牌的索引有关。type与kind.js的camptype有关

this.setData({

activeNavIndex: index,

})

let title=[]

this.data.kindTitles.forEach(kindTitle => {

if(index == kindTitle.titletype) {

title.push(kindTitle)

}

})

this.setData({

kindItem: kinds,

})

},

复制代码

绑定筛选页

gotoAssem(e) {

// console.log(e);  利用kind属性值唯一(buy页面tabs的title)

wx.navigateTo({

url: '/pages/buy_page/page/assem/assem?title='+e.currentTarget.dataset.title,

})

},

复制代码

筛选排序页


004.gif

排序页样式

08.png

<view class="page">

<view class="search" bindtap="gotoSearch">

<van-search placeholder="{{titles}}" disabled />

<view class="tab">

<view wx:for="{{tabs}}" wx:key="index" data-index="{{index}}"

class="tab-item {{activeTabIndex == index?'active': ''}}" bindtap="changeItem">

{{item.title}}

<image style="width:26rpx;height:26rpx;" src="{{item.pic}}">

复制代码

tab使用flex布局。goods部分布局参照buy页面的商品布局。

011.png

<scroll-view class="pop" scroll-y>

<van-collapse-item title="适用人群" value="全部" name="1">

<van-grid column-num="3" gutter="{{ 10 }}">

<van-grid-item class="{{activeIndex1==index?'active1':''}}">{{}}

重置

确定

复制代码

这里使用van-collapse组件做折叠面板时有个坑,不应该将van-grid内容部分放在van-collapse-item中,应与其同级,否则会在该单元格下形成留白且无法正常显示内容,多次尝试后还是放在外面方便实现效果。

初始商品排序

async onLoad(options) {

// console.log(options);

let title = options.title

let data1 = await dewuCollection

.where({

kind: title        //绑定跳转时(kind唯一)获取对应数据

}) 

.get()

// console.log(data1);

this.setData({

goods: data1.data,

titles: title

})

},

复制代码

基本排序

async changeItem(e) {  

// console.log(e);

let index = e.currentTarget.dataset.index  //index对应排序方式

this.setData({

activeTabIndex: index

})

// console.log(index);

if(index == 1) {                        //销量排序

await dewuCollection

.where({

kind: this.data.titles

})

.orderBy('buyer', 'desc') 

.get()

.then(res => {

this.setData({

goods: res.data,

index: index

})

// console.log(this.data.index);

})

}

if(index == 0) {                        //综合排序

await dewuCollection

.where({

kind: this.data.titles

})

.get()

.then(res => {

this.setData({

goods: res.data

})

})

}

if(index == 2 && this.data.flag == -1) {  //价格降序排序

await dewuCollection

.where({

kind: this.data.titles

})

.orderBy('price', 'desc') 

.get()

.then(res => {

this.setData({

goods: res.data,

flag: 1

})

})

return

}

if(index == 3) {                         //创建时间排序

await dewuCollection

.where({

kind: this.data.titles

})

.orderBy('ctime', 'desc') 

.get()

.then(res => {

this.setData({

goods: res.data

})

})

}

if(index == 4) {                         //弹出筛选层

this.setData({ 

show: true,

})

}

else if(index == 2 && this.data.flag == 1) {    //价格升序排序

await dewuCollection

.where({

kind: this.data.titles

})

.orderBy('price', 'asc') 

.get()

.then(res => {

this.setData({

goods: res.data,

flag: -1

})

})

}

},

复制代码

设置一个flag属性默认值为-1,flag==-1时点击价格降序排序并设置flag==1flag==1时点击价格升序排序并设置flag==-1

筛选排序

pick(e) {

let flag = e.currentTarget.dataset.flag

let index = e.currentTarget.dataset.index

let cd = this.data.human[index].kind

if(flag==index) {

this.setData({

activeIndex1: -1,

flag1: -1,

cd1: ''

}) 

}

else {

this.setData({

activeIndex1: index,

flag1: index,

cd1: cd

}) 

}

},

复制代码

筛选重置

replace() {    // 点击重置按钮将所有筛选条件回复默认

this.setData({

flag1: -1,

activeIndex1: -1,

flag2: -1,

activeIndex2: -1,

flag3: -1,

activeIndex3: -1,

cd1: '',

cd2: '',

cd3: 0,

cd4: 10000000,

})

},

复制代码

这里有一个坑是,不可在data中声明(num:Infinity),这里无穷大并不会生效,目前优化是声明为常量.

确认筛选

async ischeck() {   //点击确定按钮进行筛选显示结果

let cd3 = Number(this.data.cd3)

let cd4 = Number(this.data.cd4)==0?1000000:Number(this.data.cd4)

let index = Number(this.data.index)

if(this.data.cd1!='' && this.data.cd2!=''){

await dewuCollection

.where({

kind: this.data.titles,

sex: this.data.cd1,

brand: this.data.cd2,

price: .gt(cd3).and(.lt(cd4)),

})

.get()

.then(res => {

this.setData({

goods: res.data,

show: false,

})

})

return

}  

},

复制代码

难点排坑


<van-grid-item use-slot wx:for="{{shoes}}" data-item="{{item}}" 

wx:key="index" data-id="{{item._id}}" bindtap="gotoDetail">

gotoDetail(e) {

// console.log(e);

wx.navigateTo({

url: '/pages/buy_page/page/detail/detail?id='+e.currentTarget.dataset.id,

})

},      

复制代码

跳转到详情页且保留对应数据项。这里利用_id唯一,将每一项的_id赋给data-id,当id相等时才能跳转并接受对应_id的数据。

<van-grid-item class="{{activeSizeIndex==index?'size-active':''}}" 

use-slot wx:for="{{size}}" wx:key="index" data-flag="{{flag}}" 

data-index="{{index}}" bindtap="pickSize">

<view class="size">

<text id="p3">{{item.size}}

<text id="p4">¥{{item.price}}

pickSize(e) {

let flag = e.currentTarget.dataset.flag

let index = e.currentTarget.dataset.index

if(flag==index) {

this.setData({

activeSizeIndex: -1,

flag: -1

}) 

}

else {

this.setData({

activeSizeIndex: index,

flag: index

}) 

}

},

复制代码

点击尺码时选中并更改text,再次点击该项则重置样式,若点击其他项则取消选中,选中被点击项。这里通过多设一个flag,结合index双重控制是否选中。

<view 

wx:for="{{kindNav}}"

wx:key="index"

data-index="{{index}}"

data-type="{{item.type}}"

bindtap="changeKinds"

class="scroll-view-left-item {{activeNavIndex == index?'active': ''}}">

{{item.text}}

changeKinds(e) {

console.log(e);

let {index, type} = e.currentTarget.dataset;

console.log(index, type);//index与推荐品牌的索引有关。type与kind.js的camptype

this.setData({

activeNavIndex: index,

})

let kinds = []

this.data.kindall.forEach(kind => {

if(kind.camptype == type) {

kinds.push(kind)

}

})

this.setData({

kindItem: kinds,

})

}

复制代码

绑定typekind.camptype,当点击项改变时,将当前项index赋给activeNavIndex,用kindall存储所有数据项,使用foreach循环遍历kindall,将满足条件kind.camptype==type的数据存入一个数组中kinds,再将setData即可。

deleteSearchHistory() {

wx.showModal({

content: '确认清空历史记录',

success: (res) => {

if(res.confirm) {

this.setData({

historyList: []

})

}

}

})

wx.removeStorageSync('value')

},

后话


开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

对于面试,说几句个人观点。

面试,说到底是一种考试。正如我们一直批判应试教育脱离教育的本质,为了面试学习技术也脱离了技术的初心。但考试对于人才选拔的有效性是毋庸置疑的,几千年来一直如此。除非你有实力向公司证明你足够优秀,否则,还是得乖乖准备面试。这也并不妨碍你在通过面试之后按自己的方式学习。 其实在面试准备阶段,个人的收获是很大的,我也认为这是一种不错的学习方式。首先,面试问题大部分基础而且深入,这些是平时工作的基础。就好像我们之前一直不明白学习语文的意义,但它的意义就在每天的谈话间。

所谓面试造火箭,工作拧螺丝。面试往往有更高的要求,也迫使我们更专心更深入地去学习一些知识,也何尝不是一种好事。