lybenson 8 سال پیش
والد
کامیت
72ec43a522
4فایلهای تغییر یافته به همراه367 افزوده شده و 90 حذف شده
  1. 39 3
      src/App.vue
  2. 11 1
      src/components/content/BContent.vue
  3. 269 86
      src/components/nav/BNavSide.vue
  4. 48 0
      src/components/nav/smooth-scroll.js

+ 39 - 3
src/App.vue

@@ -2,9 +2,9 @@
   <div id="app">
     <TopContainer></TopContainer>
     <BHeader></BHeader>
-    <BContent></BContent>
-    <BNavSide></BNavSide>
-    <div class="wnd-mask" ref="mask"></div>
+    <BContent :items="items"></BContent>
+    <BNavSide :options="options"></BNavSide>
+    <!-- <div class="wnd-mask" ref="mask"></div> -->
   </div>
 </template>
 
@@ -20,6 +20,42 @@ export default {
     BHeader,
     BContent,
     BNavSide
+  },
+  data() {
+    return {
+      items: [{
+        name: '动画',
+        id: 'b_douga'
+      }, {
+        name: '游戏',
+        id: 'b_game'
+      }, {
+        name: '音乐',
+        id: 'b_music'
+      }, {
+        name: '舞蹈',
+        id: 'b_dance'
+      }, {
+        name: '科技',
+        id: 'b_technology'
+      }, {
+        name: '生活',
+        id: 'b_life'
+      }, {
+        name: '电影',
+        id: 'b_movie'
+      }]
+    }
+  },
+  computed: {
+    options() {
+      let options = {
+        offset: 100, //偏移的距离
+        items: this.items,
+        offsetTop: 0 //距离顶部距离
+      }
+      return options
+    }
   }
 }
 </script>

+ 11 - 1
src/components/content/BContent.vue

@@ -19,8 +19,11 @@
 			<BLive></BLive>
 		</div>
 		<!-- 各分类具体内容 -->
-		<div class="container-row"  v-for="(row, index) in rows">
+		<div class="container-row"  v-for="(row, index) in rows" :id="getContentRowId(index)">
+		
 			<BContentRow :category="sortKeys[index]" :categoryId="sortIds[index]" :row="row"></BContentRow>
+		}
+		}
 		</div>
 	</div>
 </template>
@@ -48,8 +51,15 @@ export default {
 			'sortIds'
 		])
 	},
+	props: ['items'],
 	mounted() {
 		this.$store.dispatch('getContentRows')
+		console.log(JSON.stringify(this.items[0].name) + '=======')
+	},
+	methods: {
+		getContentRowId(index) {
+			return `b_${this.items[index].id}`
+		}
 	},
 	components: {
 		Banner,

+ 269 - 86
src/components/nav/BNavSide.vue

@@ -1,122 +1,305 @@
 <template>
-	<div class="index-nav nav-side" style="opacity: 1; display: block; top: 100px; left: auto; right: 0px;">
-		<div class="border"></div>
-		<div class="nav-list">
-			<div class="n-i sortable" v-for="item in sortValues">
-				<div class="name">{{item}}</div>
+	<div class="nav-side" :class="{customizing: isSort}">
+		<transition name="fade">
+			<div v-if="isSort">
+				<div class="tip"></div>
+				<div class="custom-bg"></div>
 			</div>
-			<div class="n-i customize" title="自定义" @click="sort">
-				<i class="n-icon-sort"></i><p>排序</p>
+		</transition>
+		<div class="nav-list" ref="list">
+			<template v-for="(item, index) in data">
+				<div v-if="isDrag && index === replaceItem && replaceItem <= dragId" class="n-i sotrable">
+					<div class="name"></div>
+				</div>
+				<div class="n-i sotrable" :class="[{'on': current===index && !isSort}, {'drag': isDrag && current === index}]"  @click="setEnable(index)" @mousedown="dragStart($event, index)" :style="dragStyles">
+					<div class="name">{{item.name}}</div>
+				</div>
+				<div v-if="isDrag && index === replaceItem && replaceItem > dragId" class="n-i sotrable">
+					<div class="name"></div>
+				</div>
+			</template>
+			<li v-if="isDrag && replaceItem === data.length" :class="['sortable-item']">
+				<div class="sortable-item-name"></div>
+			</li>
+
+			<div class="n-i customize" @click="sort">
+				<i class="n-icon-sort"></i>
+				<p>排序</p>
 			</div>
 		</div>
-		<div class="n-i gotop">
+		<div class="n-i gotop" >
 			<div class="s-line"></div>
-			<div class="btn_gotop" title="返回顶部"></div>
-		</div>
-		<div class="n-i n-i-mlink">
-			<a href="#" target="_blank"  @mouseover="rotate">
-				<div class="mlink-dl-msg"></div>
-				<div class="n-i-mlink-bg" ref="mlinkBg" ></div>
-			</a>
+			<div class="btn_gotop" @click="scrollToTop(time)"></div>
 		</div>
 	</div>
 </template>
 
 <script>
-import { mapGetters } from 'vuex'
+import scrollMixin from './smooth-scroll.js'
 export default {
+	mixins: [scrollMixin],
+	data() {
+		return {
+			current: 0, //当前选中条目的序号
+			data: [], //数据(name,element,offsetTop,height)
+			time: 800, //动画时间
+			height: 32, //单个元素的高度
+			isSort: false, //排序模式
+			scrollTop: 0, //距离页面的顶部距离
+			dragId: 0, //拖拽元素序号
+			isDrag: false,  //当前是否在拖拽
+			offsetX: 0, //鼠标在要拖拽的元素上的X坐标上的偏移
+			offsetY: 0, //鼠标在要拖拽的元素上的Y坐标上的偏移
+			x: 0, //被拖拽的元素在其相对的元素上的X坐标上的偏移
+			y: 0  //被拖拽的元素在其相对的元素上的Y坐标上的偏移
+		}
+	},
+	props: {
+		options: {
+			type: Object
+		}
+	},
+	watch: {
+		//监听options的变化
+		options: {
+			deep: true,
+			handler(newVal, oldVal) {
+				this.initData()
+			}
+		}
+	},
 	computed: {
-		...mapGetters([
-			'sortValues'
-		])
+		//  偏移值
+		offset() {
+			return this.options.offset || 100
+		},
+		// 拖拽的元素的position会变为absolute,dragStyles用来设置其位置,鼠标运动时会调用,从而实现跟随鼠标运动的功能
+		dragStyles() { 
+			return {
+				left: `${this.x}px`,
+				top: `${this.y}px`
+			}
+		},
+		//当被拖拽的元素运动到其他元素的位置时,会使得replaceItem发送变化
+		replaceItem() {
+			let id = Math.floor(this.y / this.height)
+			if (id > this.data.length - 1)
+				id = this.data.length
+			if (id < 0)
+				id = 0
+			return id
+		}
+	},
+	mounted() {
+		this.init()
 	},
 	methods: {
-		rotate() {
-			console.log('开始选装')
+		/** 初始化 */
+		init() {
+			this.initData() //初始化
+			this.bindEvent()
+			this._screenHeight = window.screen.availHeight
+			this._left = this.$refs.list.getBoundingClientRect().left
+			this._top = this.$refs.list.getBoundingClientRect().top
+		},
+		/** 绑定事件 */
+		bindEvent() {
+			document.addEventListener('scroll', this.scroll, false) 
+			document.addEventListener('mousemove', this.dragMove, false)
+			document.addEventListener('mouseup', this.dragEnd, false)
+			document.addEventListener('mouseleave', this.dragEnd, false)
+		},
+		/** 初始化data */
+		initData() {
+			//将this.options.items转化成新的数组this.data
+			this.data = Array.from(this.options.items, (item) => {
+				let element = document.getElementById(item.id)
+				if (!element) {
+					console.error(`can not find element of name is ${item.id}`)
+					return
+				}
+				let offsetTop = this.getOffsetTop(element)
+				return {
+					name: item.name,
+					element: element,
+					offsetTop: offsetTop,
+					height: element.offsetHeight
+				}
+			}) 
+		},
+		setEnable(index) {
+			if (index === this.current) {
+				return false
+			}
+			this.current = index
+			let target = this.data[index].element
+			this.scrollToElem(target, this.time, this.offset || 0).then(() => {
+			})
+		},
+		//获取元素距离顶部的距离
+		getOffsetTop(element) {
+			let top, clientTop, clientLeft, scrollTop, scrollLeft,
+			doc = document.documentElement,
+			body = document.body
+			if (typeof element.getBoundingClientRect !== "undefined") {
+				top = element.getBoundingClientRect().top;
+			} else {
+				top = 0
+			}
+			clientTop = doc.clientTop || body.clientTop || 0
+			scrollTop = window.pageYOffset || doc.scrollTop
+			return (top + scrollTop - clientTop)
 		},
+		//进入排序模式
 		sort() {
-			console.log('开始排序')
+			this.isSort = !this.isSort
+		},
+		/** 得到鼠标位置 */
+		getPos(e) {
+			this.x = e.clientX - this._left - this.offsetX
+			this.y = e.clientY - this._top - this.offsetY
+		},
+		/** 滚动事件 */
+		scroll(e) {
+			this.scrollTop = window.pageYOffset || (document.documentElement.scrollTop + document.body.scrollTop)
+			for (let i = 0; i < this.data.length; i++) {
+				if (this.scrollTop >= this.data[i].offsetTop - this.offset) {
+					this.current = i
+				}
+			}
+		},
+		/** 拖拽开始 */
+		dragStart(e, i) {
+			if (!this.isSort)
+				return false
+			this.current = i
+			this.isDrag = true
+			this.dragId = i
+			this.offsetX = e.offsetX
+			this.offsetY = e.offsetY
+			this.getPos(e)
+		},
+		/** 拖拽中 */
+		dragMove(e) {
+			if (this.isDrag) {
+				this.getPos(e)
+			}
+			e.preventDefault()
+		},
+		/** 拖拽结束 */
+		dragEnd(e) {
+			if (this.isDrag) {
+				this.isDrag = false
+				if (this.replaceItem !== this.dragId) {
+					this.options.items.splice(this.replaceItem, 0, this.options.items.splice(this.dragId, 1)[0])
+				}
+				else {
+					this.setEnable(this.dragId, true)
+				}
+			}
 		}
 	}
 }
 </script>
 
 <style lang="stylus" scoped>
-	.index-nav
+	.nav-side
 		position fixed
 		width 48px
-		z-index 90
 		text-align center
+		top 0px
+		left auto
+		right 0px
+		&.customizing
+			z-index 10010
+			.n-i.sotrable
+				cursor move
 		.nav-list
 			position relative
-			z-index 250
 			background-color #f6f9fa
 			border 1px solid #e5e9ef
 			overflow hidden
 			border-radius 4px
-		.n-i
-			cursor pointer
-			&:first-child
-				border-top 0
-			.name
-				height 32px
-				line-height 32px
-				transition .1s linear
-				transition-property background-color,color
-				&:hover
-					background-color #00a1d6
-					color #fff
-			&.customize
-				padding 8px 0
-				border-top 1px solid	#e5e9ef
-				&:hover
+			z-index 233
+			.n-i
+				cursor pointer
+				&:first-child
+					border-top 0
+				&.on
+					.name
+						background-color #00a1d6
+						color #fff
+				&.customize
+					padding 8px 0
+					border-top 1px solid #e5e9ef
+					.n-icon-sort
+						display block
+						margin 0 auto 4px
+						background url(../../assets/images/icons.png) -663px -151px no-repeat
+						height 18px
+						width 18px
+				&.drag
+					position absolute
+					height 32px
+					width 100%
 					background-color #00a1d6
 					color #fff
-					.n-icon-sort
-						background-position -727px -151px
-				.n-icon-sort
-					display block
-					margin 0 auto 4px
-					background url(../../assets/images/icons.png) -663px -151px no-repeat
-					height 18px
-					width 18px
-			&.gotop
-				border 0
-				position relative
-				z-index 50
-				.s-line
-					border-left 1px solid #ddd
-					border-right 1px solid #ddd
-					height 9px
-					width 30px
-					margin 0 auto
-				.btn_gotop
-					height 48px
-					background #f6f9fa url(../../assets/images/icons.png) -648px -72px no-repeat
-					border 1px solid #e5e9ef
-					overflow hidden
-					border-radius 4px
+				.name
+					height 32px
+					line-height 32px
+					transition .1s linear
+					transition-property background-color, color
 					&:hover
 						background-color #00a1d6
-						background-position -714px -72px
-						border-color #00a1d6
-			&.n-i-mlink
-				border 0 
-				position relative
-				z-index 50
-				.mlink-dl-msg
-					background url(//i0.hdslb.com/bfs/static/3af67e81274b02ca1693fdb73adbc03c98c3880a.png)
-					width 106px
-					height 44px
-					position absolute
-					left -106px
-					top -23px
-					display none
-				.n-i-mlink-bg
-					display block
-					background-image url("//i0.hdslb.com/bfs/static/e6f2388d454c82004905753802e9cfe709d80d08.png")
-					width 80px
-					height 80px
-					background-position 0 0
-					margin-left -16px
+						color #fff
+		.gotop
+			cursor pointer
+			border 0
+			position relative
+			z-index 50
+			.s-line
+				border-left 1px solid #ddd
+				border-right 1px solid #ddd
+				height 9px
+				width 30px
+				margin 0 auto
+			.btn_gotop
+				height 48px
+				background #f6f9fa url(../../assets/images/icons.png) -648px -72px no-repeat
+				border 1px solid #e5e9ef
+				overflow hidden
+				border-radius 4px
+		.tip
+			background url(http://p1.bqimg.com/567571/f0b9b188ab580a2b.png) 0 0 no-repeat
+			position absolute
+			left -117px
+			top 0px
+			width 117px
+			height 333px
+			z-index 10
+			transition all .3s
+		.custom-bg
+			position absolute
+			top -15px
+			left -130px
+			height 100%
+			width 200px
+			padding-bottom 35px
+			box-sizing content-box
+			background rgba(255,255,255,0.8)
+			border-radius 4px
+			z-index 5
+			transition all .3s
+		.fade-enter-actice, .fade-leave-active
+			transition opacity .3s
+		.fade-enter, .fade-leave-active
+			.tip
+				top 50px
+				opacity 0
+			.custom-bg
+				top 150px
+				left -70px
+				height 100px
+				width 100px
+				opacity 0
 </style>

+ 48 - 0
src/components/nav/smooth-scroll.js

@@ -0,0 +1,48 @@
+window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame
+
+const Quad_easeIn = (t, b, c, d) => c * ((t = t / d - 1) * t * t + 1) + b
+
+const scrollTo = (end, time = 800) => {
+	let scrollTop = window.pageYOffset || document.documentElement.scrollTop
+	let b = scrollTop
+	let c = end - b
+	let d = time
+	let start = null
+
+	return new Promise((resolve, reject) => {
+		function step(timeStamp) {
+			if (start === null) start = timeStamp
+			let progress = timeStamp - start
+			if (progress < time) {
+				let st = Quad_easeIn(progress, b, c, d)
+				document.body.scrollTop = st
+				document.documentElement.scrollTop = st
+				window.requestAnimationFrame(step)
+			}
+			else {
+				document.body.scrollTop = end
+				document.documentElement.scrollTop = end
+				resolve(end)
+			}
+		}
+		window.requestAnimationFrame(step)
+	})
+}
+
+const scrollToTop = (time) => {
+	time = typeof time === 'number' ? time : 800
+	return scrollTo(0, time)
+}
+
+const scrollToElem = (elem, time, offset) => {
+	let top = elem.getBoundingClientRect().top  + ( window.pageYOffset || document.documentElement.scrollTop )  - ( document.documentElement.clientTop || 0 )
+	return scrollTo(top - (offset || 0), time)
+}
+
+export default {
+	methods: {
+		scrollToTop,
+		scrollToElem,
+		scrollTo
+	}
+}