>웹 프론트엔드 >JS 튜토리얼 >Vue 프레임워크에서 상품 구성 요소 개발

Vue 프레임워크에서 상품 구성 요소 개발

亚连
亚连원래의
2018-06-09 16:08:081383검색

이 글에서는 주로 Vue 프레임워크의 goodvs 컴포넌트 개발에 대한 자세한 설명을 소개하고 참고하겠습니다.

1. Layout Flex

Flex 레이아웃은 다양한 페이지 레이아웃을 간단하고 완전하며 반응적으로 구현할 수 있습니다. Flex는 "탄력적인 레이아웃"을 의미하는 Flex는 Box 형태의 레이아웃에 최대한의 유연성을 제공하는 데 사용됩니다. 모델. 유연성. 모든 컨테이너를 Flex 레이아웃으로 지정할 수 있습니다.

// 指定为 Flex 布局
 display: flex;
flex : 等分 内容缩放 展位空间;
flex : 0 0 80px

// 주요 속성
flex: none || flex-grow 속성은 항목의 확대 비율을 정의하며 기본값은 0입니다. 즉, 남은 공간이 있으면 확대되지 않습니다.
flex-shrink 속성은 항목의 축소 비율을 정의하며 기본값은 1, 즉 공간이 부족하면 항목이 축소되고, flex -shrink 속성은 0이고 다른 항목은 모두 1입니다. 공간이 부족하면 전자가 축소되지 않습니다. 초과 공간을 할당하기 전 항목이 차지하는 주축 공간(기본 크기)입니다. 브라우저는 이 속성을 사용하여 기본 축에 추가 공간이 있는지 계산합니다. 기본값은 프로젝트의 원래 크기인 auto입니다. 너비 또는 높이 속성과 동일한 값(예: 350px)으로 설정하면 프로젝트가 고정된 공간을 차지합니다.

2. 아이콘 구성 요소 ㅋㅋㅋ

설명(1) 원리 : 높이가 고정된 상위 컨테이너 래퍼. 첫 번째 하위 요소 콘텐츠의 높이가 래퍼의 높이를 초과하면 콘텐츠 영역을 스크롤할 수 있습니다. 높이를 초과하지 않으면 스크롤할 수 없습니다.

(2) better-scroll의 초기화

better-scroll의 초기화 시점은 매우 중요합니다. 왜냐하면 초기화 시 상위 요소와 하위 요소의 높이와 너비를 계산하여 세로로 스크롤할 수 있는지 여부를 결정하기 때문입니다. 그리고 수평으로. 따라서 초기화할 때 상위 요소와 하위 요소의 콘텐츠가 올바르게 렌더링되었는지 확인해야 합니다. 하위 요소나 상위 요소의 DOM 구조가 변경되면 정상적인 스크롤 효과를 보장하기 위해 scroll.refresh() 메서드를 다시 호출하고 다시 계산해야 합니다. 따라서 better-scroll이 스크롤할 수 없는 이유는 아마도 better-scroll을 초기화하는 타이밍이 잘못되었거나 DOM 구조가 변경 사항을 보낼 때 better-scroll이 다시 계산되지 않기 때문일 것입니다.

(3) VueVue.js와 결합하면 더 나은 스크롤이 가능해 DOM 객체(vm.$refs)를 얻기 위한 인터페이스를 제공합니다. 여기서는 this.$refs.wrapper를 통해 DOM 객체에 접근하고, 마운트된 후크 함수와 this.$nextTick의 콜백 함수에서 better-scroll을 초기화합니다. 이때 래퍼의 DOM이 렌더링되었으므로 정상적인 스크롤을 보장하기 위해 래퍼의 DOM과 내부 콘텐츠의 높이를 올바르게 계산할 수 있습니다.

This.$nextTick은 DOM이 렌더링되었는지 확인하기 위해 하단에 MutationObserver 또는 setTimeout(fn, 0)이 사용되는 비동기 함수입니다. 실제로 여기에서 this.$nextTick을 setTimeout(fn, 20)으로 대체할 수 있습니다(20ms는 경험 값이고 각 Tick은 약 17ms입니다). 이는 사용자 경험에서 감지할 수 없습니다.

(4) 비동기 데이터 처리

실제 작업에서는 목록 데이터를 비동기적으로 가져오는 경우가 많기 때문에 better-scroll을 초기화하는 시점은 데이터를 가져온 후여야 합니다. 코드는 다음과 같습니다.

<template lang="html">
 <span class="iconMap" :class="iconClassMap[iconType]"></span>
</template>

여기 requestData는 의사코드이며, 그 기능은 서버에서 데이터를 얻기 위해 http 요청을 시작하는 것이며, 이 함수는 약속을 반환합니다(실제 프로젝트에서는 axios 또는 vue-resource를 사용할 수 있습니다). Vue는 데이터 중심이므로 데이터를 얻은 후에는 비동기 방식으로 더 나은 스크롤을 초기화해야 합니다. Vue 데이터가 변경되고(this.data = res.data) 페이지가 다시 렌더링되면 비동기식입니다. 초기화 시간은 DOM이 다시 렌더링된 이후이므로 여기서는 this.$nextTick을 사용합니다. 물론 setTimeout(fn, 20)으로 대체할 수도 있습니다.

참고: 마운트된 후크 기능 대신 생성된 후크 기능에서 데이터를 요청하는 이유는 무엇입니까? requestData가 비동기 프로세스인 네트워크 요청을 보내고 있기 때문에 응답 데이터를 얻을 때 Vue의 DOM은 이미 렌더링되었지만 데이터 변경 -> DOM 재렌더링은 여전히 ​​비동기 프로세스입니다. 데이터를 비동기적으로 더 잘 초기화해야 합니다.

스크롤해야 하는 DOM 구조를 초기화하려면

을 사용하세요.

특정 DOM 요소를 바인딩하거나 구성 요소를 바인딩하려면 ref 속성을 사용한 다음 this.$refs.menuwrapper를 사용하여 해당 항목을 함수 돔.

참고: 일반 DOM 요소에 사용된 경우 참조는 DOM 요소를 가리키고, 하위 구성 요소에 사용된 경우 참조는 구성 요소 인스턴스를 가리킵니다.

export default {
 props: { // 图标类型
 iconType: Number
 },
 created() { // 数组类名
 this.iconClassMap = [&#39;decrease&#39;, &#39;discount&#39;, &#39;special&#39;, &#39;invoice&#39;, &#39;guarantee&#39;]
 }
}

ajax

에서 _initScroll() 함수를 실행하세요. 미리 준비하고 예방조치를 취해야 합니다

(1) dom结构完全加载完再调用_initScroll()方法才会生效

(2) 因为要监听内容区域的高度,所以初始化应在created过程中去监听dom结构是否完全加载,这里是在$nextTick对象中进行触发检测

ES6语法格式: this.$nextTick(() => {})

created (){ // 在实例创建完成后被立即调用 $el 属性目前不可见。
 axios.get(&#39;static/data.json&#39;).then((result) => {
 this.goods=result.data.goods
 //dom结构加载结束
 this.$nextTick(() => {
 this._initScroll(); // 初始化scroll
 })
 })
}

(3) 在methods方法里面定义一个_initScroll的函数,主要用来对左右两侧dom结构进行初始化

methods:{
 // 用来对左右两侧dom结构进行初始化
 _initScroll (){
 // 实例化 better-scroll 插件,传入要滚动的DOM 对象 
 this.meunScroll=new BScroll(this.$refs.menuWrapper,{
 click:true 
 });
 this.foodScroll=new BScroll(this.$refs.foodsWrapper,{
 click:true
 });
 
 }
 }

说明:vue中更改数据,DOM会跟着做映射,但vue更新DOM是异步的,用 $nextTick ()来确保Dom变化后能调用到_initScroll()方法。调用_initScroll()方法能计算内层ul的高度,当内层ul的高度大于外层wrapper的高度时,可以实现滚动。

此时俩侧可以分别滚动了!

(4) 实现左右联动

原理:我们计算出右侧实时变化的y值,落到哪一个区间,我们就显示那一个区间。首先我们要计算整体区间的一个高度,然后分别计算第一个区间的高度,第二个区间的高度,以此类推。然后将区间数存入一个定义好的数组。当我们在滚动的时候实时拿到y轴的高度,然后对比在哪一个区间,这样我们就会得到一个区间的索引值去对应左侧的菜品类别,最后我们用一个vue的class去绑定高亮文本。

1.定义一个方法在 _initScroll 下面,作为计算高度的方法叫做_calculateHeight () ,再定义一个listHeight:[]数组,存放获取到的每一块foods类的高度。然后通过给每个li 定义类名来供js 选择 从而计算出高度存放到listHeight数组里。

// 通过 方法 计算foods内部每一个块的高度,组成一个数组listHeight。
 // 每个li 定义一个类food-list-hook 通过获取该类 来计算 每一块的高度 存到数组listHeight里
 _calculateHeight (){
 // 获取 li 通过food-list-hook
 let foodList=this.$refs.foodsWrapper.querySelectorAll(".food-list-hook");
 let height=0;// 初始化高度
 this.listHeight.push(height) // 把第一个高度存入数组
 //通过循环foodList下的dom结构,将每一个li的高度依次送入数组
 for(let i = 0 ,l = foodList.length ; i < l ; i++){
 let item=foodList[i]; //每一个item都是刚才获取的food的每一个dom
 height += item.clientHeight; //获取每一个foods内部块的高度
 this.listHeight.push(height) // 将获取的值存放到数组里
 }
 
 }

2.我们获取到区间高度数组后,我们要实时获取到右侧的y值,和左侧的索引值做一个对比,定义一个scrollY变量用来存放实时获取的y值。bs插件为我们提供了一个实时获取y值的方法,我们在初始化this.foodScroll的时候加一个·属性probeType: 3,其作用就是实时获取y值,相当于探针的作用。

goods: [],// goods json 数组
listHeight: [],// 存放 foods 内部的每一块的高度
scrollY:0
this.foodScroll=new BScroll(this.$refs.foodsWrapper,{
 click:true,
 //探针作用,实时监测滚动位置
 probeType: 3
 });

3.我们再添加一个方法this.foodScroll.on('scroll',(pos) => {}),作用是实时滚动的时候把获取到的位置给暴露出来。代码如下。

//结合BScroll的接口使用,监听scroll事件(实时派发的),并获取鼠标坐标,当滚动时能实时暴露出scroll
 this.foodScroll.on("scroll",(pos) =>{ // 回调函数
 //scrollY接收变量 
 this.scrollY=Math.abs(Math.round(pos.y)) //滚动坐标会出现负的,并且是小数,所以需要处理一下,实时取得scrollY
 // console.log(pos.y)
 })

4.定义一个计算属性computed,获取到food滚动区域对应的menu区域的子块的索引i值,从而定位到左侧边栏的位置。

computed:{
 currentIndex (){ //计算到达哪个区域的区间的时候的对应的索引值
 // 利用 listHeight 存放 每一块 对应的高度
 for (let i=0,l=this.listHeight.length; i<l ; i++){
 let menuHeight_fir = this.listHeight[i] // 当前menu 子块区域的 高度
 let menuHeight_sec = this.listHeight[i + 1] // 下一个menu 子块区域的 高度
 // 当滑到底部时,menuHeight_sec 为 underfined,
 // 需要确定滑到俩个高度区间 
 if( !menuHeight_sec || (this.scrollY > menuHeight_fir && this.scrollY < menuHeight_sec) ){
 return i;
 }
 }
 },
 
 }

获取到i后,,然后通过设置一个class来做样式切换变化 :class="{'current':currentIndex === index}" ,当currentIndex和menu-item对应的index相等时,设置current的样式。这样就可以实现左右联动了。

<li v-for=&#39;(item,index) in goods&#39; class="menu-item" :class="index === currentIndex?&#39;menu-item-selected&#39;:&#39;menu-item&#39;">
...

在样式里提前设好 选中和正常的样式

5.最后实现左侧点击的功能。在左侧的li下绑定一个selectMenu的点击事件,并传入索引值,这样我们就可以知道点击的是哪一个li

<li v-for=&#39;(item,index) in goods&#39; class="menu-item" @click="selectMenu(index,$event)" :class="index === currentIndex?&#39;menu-item-selected&#39;:&#39;menu-item&#39;">
...
selectMenu (index, event){ // 点击左侧 ,右侧响应
 this.foodScroll.scrollTo(0, -this.listHeight[index], 300)
 }
scrollTo(x, y, time, easing)
//滚动到某个位置,x,y 代表坐标,time 表示动画时间,easing 表示缓动函数
scroll.scrollTo(0, 500)

参考: vue使用 better-scroll的参数和方法

6.关于在selectMenu中点击事件

在selectMenu中点击,在pc界面会出现两次事件,在移动端就只出现一次事件的问题

原因 : better-scroll 会监听事件(例如touchmove,click之类),并且阻止默认事件(prevent stop),并且他只会监听移动端的,pc端的没有监听

在pc页面上 better-scroll 也派发了一次click事件,原生也派发了一次click事件

// better-scroll 的事件,有_constructed: true
MouseEvent {isTrusted: false, _constructed: true, screenX: 0, screenY: 0, clientX: 0…}
//pc的事件
MouseEvent {isTrusted: true, screenX: -1867, screenY: 520, clientX: 53, clientY: 400…}

解决 : 针对better-scroll 的事件,有_constructed: true,所以做处理,return掉非better-scroll 的事件

selectMenu(index, event){
 if (!event._constructed) { //去掉自带的click事件点击,即pc端直接返回
 return;
 }
 let foodList=this.$refs.foodsWrapper.querySelectorAll(".food-list-hook"); // 获得监听元素
 let el = foodList[index]; // 获得 当前 监听元素的高度 
 this.foodScroll.scrollToElement(el, 300); //类似jump to的功能,通过这个方法,跳转到指定的dom
 }

goods 组件到此差不多了!

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

使用原生JavaScript实现放大镜效果

在nodejs中通过redis作为缓存实现的封装缓存类

Vue Socket.io源码详细分析

vue中调用methods的方法

Vue组件通信(详细教程)

위 내용은 Vue 프레임워크에서 상품 구성 요소 개발의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.