国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服務器之家 - 編程語言 - JavaScript - js教程 - 前端如何實現動畫過渡效果

前端如何實現動畫過渡效果

2022-01-17 16:37donglegend js教程

這篇文章主要介紹了前端如何實現動畫過渡效果,幫助大家更好的理解和學習前端開發網頁,感興趣的朋友可以了解下

簡介

動畫這個概念非常寬泛,涉及各個領域,這里我們把范圍縮小到前端網頁應用層面上,不用講游戲領域的Animate,一切從最簡單的開始。

目前大部分網頁應用都是基于框架開發的,比如Vue,React等,它們都是基于數據驅動視圖的,那么讓我們來對比一下,還沒有這些框架的時候我們如何實現動畫或者過渡效果,然后使用數據驅動又是如何實現的。

傳統過渡動畫

動畫效果對體驗有著非常重要的效果,但是對于很多開發者來講,可能是個非常薄弱的環節。在css3出現之后,很多初學者最常用的動畫過渡可能就是css3的能力了。

css過渡動畫

css啟動過渡動畫非常簡單,書寫transition屬性就可以了,下面寫一個demo

?
1
<div id="app" class="normal"></div>
?
1
2
3
4
5
6
7
8
9
10
11
.normal {
  width: 100px;
  height: 100px;
  background-color: red;
  transition: all 0.3s;
}
.normal:hover {
  background-color: yellow;
  width: 200px;
  height: 200px;
}

效果還是很贊的,css3的transition基本滿足了大部分動畫需求,如果不滿足還有真正的css3 animation。

animate-css

大名鼎鼎的css動畫庫,誰用誰知道。

不管是css3 transition 還是 css3 animation,我們簡單使用都是通過切換class類名,如果要做回調處理,瀏覽器也提供了 ontransitionend , onanimationend等動畫幀事件,通過js接口進行監聽即可。

?
1
2
3
4
5
6
7
var el = document.querySelector('#app')
el.addEventListener('transitionstart', () => {
  console.log('transition start')
})
el.addEventListener('transitionend', () => {
  console.log('transition end')
})

ok,這就是css動畫的基礎了,通過js封裝也可以實現大部分的動畫過渡需求,但是局限性在與只能控制css支持的屬性動畫,相對來說控制力還是稍微弱一點。

js動畫

js畢竟是自定義編碼程序,對于動畫的控制力就很強大了,而且能實現各種css不支持的效果。 那么 js 實現動畫的基礎是什么?
簡單來講,所謂動畫就是在 時間軸上不斷更新某個元素的屬性,然后交給瀏覽器重新繪制,在視覺上就成了動畫。廢話少說,還是先來個栗子:

?
1
<div id="app" class="normal"></div>
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Tween僅僅是個緩動函數
var el = document.querySelector('#app')
var time = 0, begin = 0, change = 500, duration = 1000, fps = 1000 / 60;
function startSport() {
  var val = Tween.Elastic.easeInOut(time, begin, change, duration);
  el.style.transform = 'translateX(' + val + 'px)';
  if (time <= duration) {
    time += fps
  } else {
    console.log('動畫結束重新開始')
    time = 0;
  }
  setTimeout(() => {
    startSport()
  }, fps)
}
startSport()

在時間軸上不斷更新屬性,可以通過setTimeout或者requestAnimation來實現。至于Tween緩動函數,就是類似于插值的概念,給定一系列變量,然后在區間段上可以獲取任意時刻的值,純數學公式,幾乎所有的動畫框架都會使用,想了解的可以參考張鑫旭的Tween.js

OK,這個極簡demo也是js實現動畫的核心基礎了,可以看到我們通過程序完美的控制了過渡值的生成過程,所有其他復雜的動畫機制都是這個模式。

傳統和Vue/React框架對比

通過前面的例子,無論是css過渡還是js過渡,我們都是直接獲取到 dom元素的,然后對dom元素進行屬性操作。
Vue/React都引入了虛擬dom的概念,數據驅動視圖,我們盡量不去操作dom,只控制數據,那么我們如何在數據層面驅動動畫呢?

Vue框架下的過渡動畫

可以先看一遍文檔

Vue過渡動畫

我們就不講如何使用了,我們來分析一下Vue提供的transition組件是如何實現動畫過渡支持的。

transition組件

先看transition組件代碼,路徑 “src/platforms/web/runtime/components/transition.js”
核心代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// 輔助函數,復制props的數據
export function extractTransitionData (comp: Component): Object {
 const data = {}
 const options: ComponentOptions = comp.$options
 // props
 for (const key in options.propsData) {
  data[key] = comp[key]
 }
 // events.
 const listeners: ?Object = options._parentListeners
 for (const key in listeners) {
  data[camelize(key)] = listeners[key]
 }
 return data
}
 
export default {
 name: 'transition',
 props: transitionProps,
 abstract: true, // 抽象組件,意思是不會真實渲染成dom,輔助開發
 
 render (h: Function) {
  // 通過slots獲取到真實渲染元素children
  let children: any = this.$slots.default
  
  const mode: string = this.mode
 
  const rawChild: VNode = children[0]
 
  // 添加唯一key
  // component instance. This key will be used to remove pending leaving nodes
  // during entering.
  const id: string = `__transition-${this._uid}-`
  child.key = getKey(id)
    : child.key
  // data上注入transition屬性,保存通過props傳遞的數據
  const data: Object = (child.data || (child.data = {})).transition = extractTransitionData(this)
  const oldRawChild: VNode = this._vnode
  const oldChild: VNode = getRealChild(oldRawChild)
 
  
   // important for dynamic transitions!
   const oldData: Object = oldChild.data.transition = extend({}, data)
 // handle transition mode
   if (mode === 'out-in') {
    // return placeholder node and queue update when leave finishes
    this._leaving = true
    mergeVNodeHook(oldData, 'afterLeave', () => {
     this._leaving = false
     this.$forceUpdate()
    })
    return placeholder(h, rawChild)
   } else if (mode === 'in-out') {
    let delayedLeave
    const performLeave = () => { delayedLeave() }
    mergeVNodeHook(data, 'afterEnter', performLeave)
    mergeVNodeHook(data, 'enterCancelled', performLeave)
    mergeVNodeHook(oldData, 'delayLeave', leave => { delayedLeave = leave })
   }
  return rawChild
 }
}

可以看到,這個組件本身功能比較簡單,就是通過slots拿到需要渲染的元素children,然后把 transition的props屬性數據copy到data的transtion屬性上,供后續注入生命周期使用,mergeVNodeHook就是做生命周期管理的。

modules/transition

接著往下看生命周期相關,路徑:
src/platforms/web/runtime/modules/transition.js
先看默認導出:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function _enter (_: any, vnode: VNodeWithData) {
 if (vnode.data.show !== true) {
  enter(vnode)
 }
}
export default inBrowser ? {
 create: _enter,
 activate: _enter,
 remove (vnode: VNode, rm: Function) {
  if (vnode.data.show !== true) {
   leave(vnode, rm)
  }
 }
} : {}

這里inBrowser就當做true,因為我們分析的是瀏覽器環境。
接著看enter 和 leave函數,先看enter:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
export function addTransitionClass (el: any, cls: string) {
 const transitionClasses = el._transitionClasses || (el._transitionClasses = [])
 if (transitionClasses.indexOf(cls) < 0) {
  transitionClasses.push(cls)
  addClass(el, cls)
 }
}
 
export function removeTransitionClass (el: any, cls: string) {
 if (el._transitionClasses) {
  remove(el._transitionClasses, cls)
 }
 removeClass(el, cls)
}
export function enter (vnode: VNodeWithData, toggleDisplay: ?() => void) {
 const el: any = vnode.elm
 
 // call leave callback now
 if (isDef(el._leaveCb)) {
  el._leaveCb.cancelled = true
  el._leaveCb()
 }
 // 上一步注入data的transition數據
 const data = resolveTransition(vnode.data.transition)
 if (isUndef(data)) {
  return
 }
 
 /* istanbul ignore if */
 if (isDef(el._enterCb) || el.nodeType !== 1) {
  return
 }
 
 const {
  css,
  type,
  enterClass,
  enterToClass,
  enterActiveClass,
  appearClass,
  appearToClass,
  appearActiveClass,
  beforeEnter,
  enter,
  afterEnter,
  enterCancelled,
  beforeAppear,
  appear,
  afterAppear,
  appearCancelled,
  duration
 } = data
 
 
 let context = activeInstance
 let transitionNode = activeInstance.$vnode
 
 const isAppear = !context._isMounted || !vnode.isRootInsert
 
 if (isAppear && !appear && appear !== '') {
  return
 }
 // 獲取合適的時機應該注入的className
 const startClass = isAppear && appearClass
  ? appearClass
  : enterClass
 const activeClass = isAppear && appearActiveClass
  ? appearActiveClass
  : enterActiveClass
 const toClass = isAppear && appearToClass
  ? appearToClass
  : enterToClass
 
 const beforeEnterHook = isAppear
  ? (beforeAppear || beforeEnter)
  : beforeEnter
 const enterHook = isAppear
  ? (typeof appear === 'function' ? appear : enter)
  : enter
 const afterEnterHook = isAppear
  ? (afterAppear || afterEnter)
  : afterEnter
 const enterCancelledHook = isAppear
  ? (appearCancelled || enterCancelled)
  : enterCancelled
 
 const explicitEnterDuration: any = toNumber(
  isObject(duration)
   ? duration.enter
   : duration
 )
 
 const expectsCSS = css !== false && !isIE9
 const userWantsControl = getHookArgumentsLength(enterHook)
 // 過渡結束之后的回調處理,刪掉進入時的class
 const cb = el._enterCb = once(() => {
  if (expectsCSS) {
   removeTransitionClass(el, toClass)
   removeTransitionClass(el, activeClass)
  }
  if (cb.cancelled) {
   if (expectsCSS) {
    removeTransitionClass(el, startClass)
   }
   enterCancelledHook && enterCancelledHook(el)
  } else {
   afterEnterHook && afterEnterHook(el)
  }
  el._enterCb = null
 })
 
 
 // dom進入時,添加start class進行過渡
 beforeEnterHook && beforeEnterHook(el)
 if (expectsCSS) {
  // 設置過渡開始之前的默認樣式
  addTransitionClass(el, startClass)
  addTransitionClass(el, activeClass)
  // 瀏覽器渲染下一幀 刪除默認樣式,添加toClass
  // 添加end事件監聽,回調就是上面的cb
  nextFrame(() => {
   removeTransitionClass(el, startClass)
   if (!cb.cancelled) {
    addTransitionClass(el, toClass)
    if (!userWantsControl) {
     if (isValidDuration(explicitEnterDuration)) {
      setTimeout(cb, explicitEnterDuration)
     } else {
      whenTransitionEnds(el, type, cb)
     }
    }
   }
  })
 }
 
 if (vnode.data.show) {
  toggleDisplay && toggleDisplay()
  enterHook && enterHook(el, cb)
 }
 
 if (!expectsCSS && !userWantsControl) {
  cb()
 }
}

enter里使用了一個函數whenTransitionEnds,其實就是監聽過渡或者動畫結束的事件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
export let transitionEndEvent = 'transitionend'
export let animationEndEvent = 'animationend'
export function whenTransitionEnds (
 el: Element,
 expectedType: ?string,
 cb: Function
) {
 const { type, timeout, propCount } = getTransitionInfo(el, expectedType)
 if (!type) return cb()
 const event: string = type === TRANSITION ? transitionEndEvent : animationEndEvent
 let ended = 0
 const end = () => {
  el.removeEventListener(event, onEnd)
  cb()
 }
 const onEnd = e => {
  if (e.target === el) {
   if (++ended >= propCount) {
    end()
   }
  }
 }
 setTimeout(() => {
  if (ended < propCount) {
   end()
  }
 }, timeout + 1)
 el.addEventListener(event, onEnd)
}

OK,到了這里,根據上面源代碼的注釋分析,我們可以發現:

  • Vue先是封裝了一些列操作dom className的輔助方法addClass/removeClass等。
  • 然后在生命周期enterHook之后,馬上設置了startClass也就是enterClass的默認初始樣式,還有activeClass
  • 緊接著在瀏覽器nextFrame下一幀,移除了startClass,添加了toClass,并且添加了過渡動畫的end事件監聽處理
  • 監聽到end事件之后,調動cb,移除了toClass和activeClass

leave的過程和enter的處理過程是一樣,只不過是反向添加移除className

結論:Vue的動畫過渡處理方式和 傳統dom本質上是一樣,只不過融入了Vue的各個生命周期里進行處理,本質上還是在dom 添加刪除的時機進行處理

React里的過渡動畫

噢,我們翻篇了React的文檔,也沒有發現有過渡動畫的處理。嘿,看來官方不原生支持。

但是我們可以自己實現,比如通過useState維護一個狀態,在render里根據狀態進行className的切換,但是復雜的該怎么辦?

所幸在社區找到了一個輪子插件react-transition-group
嗯,直接貼源碼,有了前面Vue的分析,這個非常容易理解,反而更簡單:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
class Transition extends React.Component {
 static contextType = TransitionGroupContext
 
 constructor(props, context) {
  super(props, context)
  let parentGroup = context
  let appear =
   parentGroup && !parentGroup.isMounting ? props.enter : props.appear
 
  let initialStatus
 
  this.appearStatus = null
 
  if (props.in) {
   if (appear) {
    initialStatus = EXITED
    this.appearStatus = ENTERING
   } else {
    initialStatus = ENTERED
   }
  } else {
   if (props.unmountOnExit || props.mountOnEnter) {
    initialStatus = UNMOUNTED
   } else {
    initialStatus = EXITED
   }
  }
 
  this.state = { status: initialStatus }
 
  this.nextCallback = null
 }
 
 // 初始dom的時候,更新默認初始狀態
 componentDidMount() {
  this.updateStatus(true, this.appearStatus)
 }
 // data更新的時候,更新對應的狀態
 componentDidUpdate(prevProps) {
  let nextStatus = null
  if (prevProps !== this.props) {
   const { status } = this.state
 
   if (this.props.in) {
    if (status !== ENTERING && status !== ENTERED) {
     nextStatus = ENTERING
    }
   } else {
    if (status === ENTERING || status === ENTERED) {
     nextStatus = EXITING
    }
   }
  }
  this.updateStatus(false, nextStatus)
 }
 
 updateStatus(mounting = false, nextStatus) {
  if (nextStatus !== null) {
   // nextStatus will always be ENTERING or EXITING.
   this.cancelNextCallback()
 
   if (nextStatus === ENTERING) {
    this.performEnter(mounting)
   } else {
    this.performExit()
   }
  } else if (this.props.unmountOnExit && this.state.status === EXITED) {
   this.setState({ status: UNMOUNTED })
  }
 }
 
 performEnter(mounting) {
  const { enter } = this.props
  const appearing = this.context ? this.context.isMounting : mounting
  const [maybeNode, maybeAppearing] = this.props.nodeRef
   ? [appearing]
   : [ReactDOM.findDOMNode(this), appearing]
 
  const timeouts = this.getTimeouts()
  const enterTimeout = appearing ? timeouts.appear : timeouts.enter
  // no enter animation skip right to ENTERED
  // if we are mounting and running this it means appear _must_ be set
  if ((!mounting && !enter) || config.disabled) {
   this.safeSetState({ status: ENTERED }, () => {
    this.props.onEntered(maybeNode)
   })
   return
  }
 
  this.props.onEnter(maybeNode, maybeAppearing)
 
  this.safeSetState({ status: ENTERING }, () => {
   this.props.onEntering(maybeNode, maybeAppearing)
 
   this.onTransitionEnd(enterTimeout, () => {
    this.safeSetState({ status: ENTERED }, () => {
     this.props.onEntered(maybeNode, maybeAppearing)
    })
   })
  })
 }
 
 performExit() {
  const { exit } = this.props
  const timeouts = this.getTimeouts()
  const maybeNode = this.props.nodeRef
   ? undefined
   : ReactDOM.findDOMNode(this)
 
  // no exit animation skip right to EXITED
  if (!exit || config.disabled) {
   this.safeSetState({ status: EXITED }, () => {
    this.props.onExited(maybeNode)
   })
   return
  }
 
  this.props.onExit(maybeNode)
 
  this.safeSetState({ status: EXITING }, () => {
   this.props.onExiting(maybeNode)
 
   this.onTransitionEnd(timeouts.exit, () => {
    this.safeSetState({ status: EXITED }, () => {
     this.props.onExited(maybeNode)
    })
   })
  })
 }
 
 cancelNextCallback() {
  if (this.nextCallback !== null) {
   this.nextCallback.cancel()
   this.nextCallback = null
  }
 }
 
 safeSetState(nextState, callback) {
  // This shouldn't be necessary, but there are weird race conditions with
  // setState callbacks and unmounting in testing, so always make sure that
  // we can cancel any pending setState callbacks after we unmount.
  callback = this.setNextCallback(callback)
  this.setState(nextState, callback)
 }
 
 setNextCallback(callback) {
  let active = true
 
  this.nextCallback = event => {
   if (active) {
    active = false
    this.nextCallback = null
 
    callback(event)
   }
  }
 
  this.nextCallback.cancel = () => {
   active = false
  }
 
  return this.nextCallback
 }
 // 監聽過渡end
 onTransitionEnd(timeout, handler) {
  this.setNextCallback(handler)
  const node = this.props.nodeRef
   ? this.props.nodeRef.current
   : ReactDOM.findDOMNode(this)
 
  const doesNotHaveTimeoutOrListener =
   timeout == null && !this.props.addEndListener
  if (!node || doesNotHaveTimeoutOrListener) {
   setTimeout(this.nextCallback, 0)
   return
  }
 
  if (this.props.addEndListener) {
   const [maybeNode, maybeNextCallback] = this.props.nodeRef
    ? [this.nextCallback]
    : [node, this.nextCallback]
   this.props.addEndListener(maybeNode, maybeNextCallback)
  }
 
  if (timeout != null) {
   setTimeout(this.nextCallback, timeout)
  }
 }
 
 render() {
  const status = this.state.status
 
  if (status === UNMOUNTED) {
   return null
  }
 
  const {
   children,
   // filter props for `Transition`
   in: _in,
   mountOnEnter: _mountOnEnter,
   unmountOnExit: _unmountOnExit,
   appear: _appear,
   enter: _enter,
   exit: _exit,
   timeout: _timeout,
   addEndListener: _addEndListener,
   onEnter: _onEnter,
   onEntering: _onEntering,
   onEntered: _onEntered,
   onExit: _onExit,
   onExiting: _onExiting,
   onExited: _onExited,
   nodeRef: _nodeRef,
   ...childProps
  } = this.props
 
  return (
   // allows for nested Transitions
   <TransitionGroupContext.Provider value={null}>
    {typeof children === 'function'
     ? children(status, childProps)
     : React.cloneElement(React.Children.only(children), childProps)}
   </TransitionGroupContext.Provider>
  )
 }
}

可以看到,和Vue是非常相似的,只不過這里變成了在React的各個生命周期函數了進行處理。

到了這里,我們會發現不管是Vue的transiton組件,還是React這個transiton-group組件,著重處理的都是css屬性的動畫。

數據驅動的動畫

而實際場景中總是會遇到css無法處理的動畫,這個時候,可以有兩種解決方案:

通過ref獲取dom,然后采用我們傳統的js方案。
通過state狀態維護繪制dom的數據,不斷通過setState更新state類驅動視圖自動刷新

以上就是前端如何實現動畫過渡效果的詳細內容,更多關于前端實現動畫過渡效果的資料請關注服務器之家其它相關文章!

原文鏈接:https://segmentfault.com/a/1190000039173935

延伸 · 閱讀

精彩推薦
  • js教程基于JavaScript實現簡單掃雷游戲

    基于JavaScript實現簡單掃雷游戲

    這篇文章主要介紹了基于JavaScript實現簡單掃雷游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    北冰洋_WH4382021-12-23
  • js教程Javascript生成器(Generator)的介紹與使用

    Javascript生成器(Generator)的介紹與使用

    這篇文章主要給大家介紹了關于Javascript生成器(Generator)的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值...

    瘋狂的技術宅3362022-01-12
  • js教程繪制微信小程序驗證碼功能的實例代碼

    繪制微信小程序驗證碼功能的實例代碼

    這篇文章主要介紹了繪制微信小程序驗證碼功能的實例代碼,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參...

    WALL*E8802021-12-27
  • js教程three.js顯示中文字體與tween應用詳析

    three.js顯示中文字體與tween應用詳析

    這篇文章主要給大家介紹了關于three.js顯示中文字體與tween應用的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習...

    郭志強9892021-12-24
  • js教程詳解javascript腳本何時會被執行

    詳解javascript腳本何時會被執行

    這篇文章主要介紹了詳解javascript腳本何時會被執行,幫助大家更好的理解和使用JavaScript,感興趣的朋友可以了解下...

    皮卡丘和羊寶貝6682022-01-17
  • js教程js動態生成表格(節點操作)

    js動態生成表格(節點操作)

    這篇文章主要為大家詳細介紹了js動態生成表格,進行節點操作,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    劉劉劉code3582021-12-30
  • js教程在JavaScript中查找字符串中最長單詞的三種方法(推薦)

    在JavaScript中查找字符串中最長單詞的三種方法(推薦)

    這篇文章主要介紹了在JavaScript中查找字符串中最長單詞的三種方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋...

    Hunter網絡安全7332022-01-04
  • js教程JS+CSS實現過渡特效

    JS+CSS實現過渡特效

    這篇文章主要為大家詳細介紹了JS+CSS實現過渡特效,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    Dr_空山3602021-12-23
主站蜘蛛池模板: 久久久久久日产精品 | 欧美成人精品一区二区三区 | 久久伊人亚洲 | 欧美狠狠 | 国产伦精品一区二区三区四区视频_ | 久久久久久久一区 | 国产香蕉视频 | 久久免费视频观看 | av软件在线 | 国产精品久久久久久久久 | 亚洲精品久久久久久下一站 | 国产精品美女久久久久久久久久久 | 久久久久久亚洲 | 精品久久99| 中文视频在线 | 久久精彩视频 | 国产成人精品综合 | 日韩专区中文字幕 | 午夜在线观看视频网站 | 中文字幕一区在线观看视频 | 黄色直接看 | 四虎永久在线观看 | 亚洲一区二区免费视频 | 黄色成人av| 国产资源在线视频 | 日韩一区二区三区精品 | 国产一级高清视频 | 羞羞视频免费观看 | 97国产一区二区精品久久呦 | 免费看国产 | 国产精品美女久久久 | 午夜黄色影院 | 成人在线播放 | 亚洲国产精品尤物yw在线观看 | 亚洲人人 | 超碰在线免费福利 | 天堂在线中文字幕 | 成人网在线视频 | 中文字幕 亚洲一区 | 99视频这里有精品 | 久在线视频 |