この記事では主にVueフレームワークのgoodvsコンポーネント開発の詳細な説明を紹介し、参考にしていきます。
1. レイアウト Flex
Flex レイアウトは、さまざまなページ レイアウトを簡単、完全、レスポンシブに実現できます。Flex は、「柔軟なレイアウト」を意味する、ボックス型の最大限の柔軟性を提供するために使用されます。モデル。任意のコンテナを Flex レイアウトとして指定できます。
// 指定为 Flex 布局 display: flex;
flex : 等分 内容缩放 展位空间; flex : 0 0 80px
// 主な属性
flex: none | [ <'flex-grow'<'flex-shrink'> || flex 属性はflex - 拡張、フレックスシュリンク、およびフレックスベースの略語。デフォルト値は 0 1 auto です。最後の 2 つのプロパティはオプションです。
flex-grow 属性はアイテムの拡大率を定義します。デフォルトは 0 です。つまり、スペースが残っている場合は拡大されません。
flex-shrink 属性はアイテムの縮小率を定義します。デフォルトは1、つまり、スペースが不十分な場合、項目は縮小します。 flex -shrink 属性は 0 で、他のすべての項目は 1 です。スペースが不十分な場合、前者は縮小しません。余分なスペースを割り当てる前にアイテムが占有する主軸スペース (メイン サイズ)。ブラウザはこの属性を使用して、主軸に余分なスペースがあるかどうかを計算します。デフォルト値はプロジェクトの元のサイズである auto で、幅または高さの属性と同じ値 (350px など) に設定されている場合、プロジェクトは固定スペースを占有します
サブコンポーネントのアイコンマップ
<template lang="html"> <span class="iconMap" :class="iconClassMap[iconType]"></span> </template>
親コンポーネントの商品
export default { props: { // 图标类型 iconType: Number }, created() { // 数组类名 this.iconClassMap = ['decrease', 'discount', 'special', 'invoice', 'guarantee'] } }
スクロール効果を実現するiscrollに似ています
インストール
import iconMap from '../iconMap/iconMap' // 注意路径写法 // 注册组件 components: { iconMap }
概要
<ul> <li v-for='(item,index) in goods' class="menu-item"> <span class="text"> // json 数据 根据 type 判断 是否有图标 <iconMap v-show="item.type>0" :iconType="item.type"></iconMap> {{item.name}} </span> </li> </ul>
説明
(1) 原則: 固定の高さを持つ親コンテナ ラッパー。最初の子要素のコンテンツの高さがラッパーの高さを超える場合、コンテンツ領域をスクロールできます。それが高さを超えない場合は、スクロールできません。
(2) better-scroll の初期化
better-scroll は初期化時に親要素と子要素の高さと幅を計算してスクロール可能かどうかを判断するため、初期化のタイミングが非常に重要です。垂直方向と水平方向。したがって、初期化するときは、親要素と子要素のコンテンツが正しくレンダリングされていることを確認する必要があります。子要素または親要素の DOM 構造が変更された場合は、通常のスクロール効果を確保するために、scroll.refresh() メソッドを再度呼び出して再計算する必要があります。したがって、better-scroll がスクロールできない理由は、better-scroll の初期化のタイミングが間違っているか、DOM 構造が変更を送信するときに better-scroll が再計算されないことが考えられます。
(3) Vue
Vue.js と組み合わせた better-scroll は、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) に置き換えることができます (20 ミリ秒は経験値であり、各 Tick は約 17 ミリ秒です)。これはユーザー エクスペリエンスには認識できません。
(4) 非同期データ処理
実際の作業では、リストデータを非同期で取得することが多いため、better-scrollの初期化タイミングはデータ取得後に行う必要があります。 コードは以下の通りです。
ここで requestData は擬似コードであり、その機能はサーバーからデータを取得するために http リクエストを開始することであり、この関数は Promise を返します (実際のプロジェクトでは axios または vue-resource を使用する場合があります)。 Vue はデータ駆動型であるため、データを取得した後、非同期で better-scroll を初期化する必要があります。Vue データが変更され (this.data = res.data)、ページが再レンダリングされると、それは非同期になります。初期化時間は DOM が再レンダリングされた後なので、ここでは this.$nextTick を使用します。もちろん、setTimeout(fn, 20) に置き換えることもできます。 注: データがマウントされたフック関数ではなく、作成されたフック関数で要求されるのはなぜですか? requestData は非同期プロセスであるネットワーク リクエストを送信しているため、応答データを取得した時点では Vue の DOM はすでにレンダリングされていますが、データが変更される -> DOM の再レンダリングは依然として非同期プロセスであるため、取得後であっても。データに加えて、better-scroll を非同期的に初期化する必要もあります。スクロールする必要がある dom 構造を初期化するには
を使用します
ref 属性を使用して特定の dom 要素をバインドするか、コンポーネントをバインドし、this.$refs.menuwrapper を使用してそれを取得します機能ドム。 注: 通常の DOM 要素で使用される場合、参照は DOM 要素を指します。サブコンポーネントで使用される場合、参照はコンポーネント インスタンスを指します:npm install better-scroll
ここで事前にいくつかの準備と注意が必要です
(1) dom结构完全加载完再调用_initScroll()方法才会生效
(2) 因为要监听内容区域的高度,所以初始化应在created过程中去监听dom结构是否完全加载,这里是在$nextTick对象中进行触发检测
ES6语法格式: this.$nextTick(() => {})
created (){ // 在实例创建完成后被立即调用 $el 属性目前不可见。 axios.get('static/data.json').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='(item,index) in goods' class="menu-item" :class="index === currentIndex?'menu-item-selected':'menu-item'"> ...
在样式里提前设好 选中和正常的样式
5.最后实现左侧点击的功能。在左侧的li下绑定一个selectMenu的点击事件,并传入索引值,这样我们就可以知道点击的是哪一个li
<li v-for='(item,index) in goods' class="menu-item" @click="selectMenu(index,$event)" :class="index === currentIndex?'menu-item-selected':'menu-item'"> ...
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 组件到此差不多了!
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
以上がVueフレームワークでの商品コンポーネントの開発の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。