项目实战【vue,react,微信小程序】(1707B)

目录

一、transition过渡动画

二、比较两个对象是否相等

三、图片懒加载使用gif图做loading

四、图片懒加载使用动画做loading

五、forEach

六、vuex getters

七、详情页对象变更检查注意事项

八、对话框组件

九、自定义alert,全局函数使用

十、瀑布流

十一、reduce和immutable.js

十二、使用immutable实现对象深拷贝

十三、路由懒加载

十四、小程序自定义对话框组件

十五、小程序案例

github源代码:


 

 

 

 

 

 

 

 

 

 

 

 

 

 

一、transition过渡动画

项目实战【vue,react,微信小程序】(1707B)_第1张图片

过渡:





动画:





二、比较两个对象是否相等

使用immutable:





  
  immutable.js实例
  



  
  


 使用原生js(核心代码):

    function compare2Objects(x, y) {
      for (let p in x) {
        // if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
        //   return false;
        // } else if (typeof y[p] !== typeof x[p]) {
        //   return false;
        // }
        
        switch (typeof (x[p])) {
          case 'object':
            if (!compare2Objects(x[p], y[p])) {
              return false;
            }
            break;
          default:
            if (x[p] !== y[p]) {
              return false;
            }
            break;
        }
      }

      return true;
    }

    let obj3 = {
      a: {
        b: 1,
        c: [1, 2]
      }
    }

    let obj4 = {
      a: {
        b: 1,
        c: [1, 3]
      }
    }

    console.log(compare2Objects(obj3, obj4))

 

详细代码请参考:

https://www.jianshu.com/p/90ed8b728975

三、图片懒加载使用gif图做loading

项目实战【vue,react,微信小程序】(1707B)_第2张图片

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import lazyload from 'vue-lazyload'
import './index.css'
import loading from './images/loading.gif'

Vue.use(lazyload, {
  loading: loading
})

Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')
    
{{item.title}}
.m-list-item{display: flex;margin: 5px;}
.m-img-wrap{display: flex; width: 122px;height: 150px;background: #dddddd;}
.m-img{width: 122px;height: 150px;}
.m-img[lazy=loading]{margin: auto; width: 38px;height: 38px;}
.m-info{flex:1}

四、图片懒加载使用动画做loading

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import lazyload from 'vue-lazyload'
import './index.css'


Vue.use(lazyload)

Vue.config.productionTip = false

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')
    
{{item.title}}
.m-list-item{display: flex;margin: 5px;}
.m-img-wrap{display: flex; width: 122px;height: 150px;background: #dddddd;}
.m-img-wrap::before{content: '';margin: auto;width: 38px;height: 38px;background-image: url(./images/loading.png);animation: loading 1s linear infinite;}
.m-img{position: absolute; width: 122px;height: 150px;}
.m-img[lazy=loading]{margin: auto; width: 38px;height: 38px;}
.m-info{flex:1}

@keyframes loading {
  0% {transform: rotate(0);}
  100%{transform: rotate(360deg);}
}

五、forEach

在forEach中,不能使用 continue 和 break ,可以使用 return 或 return false 跳出循环,效果与 for 中 continue 一样。注意该方法无法一次结束所有循环,需要一次性结束所有循环,还是老老实实使用for方法。

var arr = ['a', 'b', 'c', 'd', 'e'];
arr.forEach(function(item, index) {
    if (item === 'b') {
        return true;  //相当于continue
    }
    if (item === 'c') {
        return false;  //相当于continue
    }
    console.log(index + ':' + item);
});

项目实战【vue,react,微信小程序】(1707B)_第3张图片

六、vuex getters

通过属性访问:

  getters: {
    getCurrentList(state) {
      return state.currentList
    }
  },
export default {
  computed: {
    list() {
      return this.$store.getters.getCurrentList
    }
  }
}

通过方法访问:

  getters: {
    getTaskList(state) {
      return (type, search) => {
        return state.taskList.filter(item => {
          if (type) {
            return item.type === type
          } else {
            return true
          }
        }).filter(item => {
          if (search) {
            return item.name.includes(search)
          } else {
            return true
          }
        })
      }
    }
  },
  methods: {
    handleTask(type) {
      this.taskList = this.$store.getters.getTaskList(type, this.search)
      this.type = type
      console.log(this.taskList)
    },
    handleSearch() {
      this.taskList = this.$store.getters.getTaskList(this.type, this.search)
      console.log(this.taskList)
    }
  },

七、详情页对象变更检查注意事项

 





参考链接:

https://cn.vuejs.org/v2/guide/list.html#%E5%AF%B9%E8%B1%A1%E5%8F%98%E6%9B%B4%E6%A3%80%E6%B5%8B%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9

 

八、对话框组件

Dialog.vue:





css:

.m-dialog-wrap{display: none;position: fixed;top: 0;left: 0;right: 0;bottom: 0;background: rgba(0, 0, 0, 0.2);}
.m-dialog-wrap.active{display: flex;}
.m-dialog{display: flex;flex-direction: column; margin: auto;padding: 10px; min-width: 200px;min-height: 150px; background: #ffffff;border-radius: 5px;}
.m-dialog-title{line-height: 50px;font-weight: bold;}
.m-dialog-content{flex: 1;}
.m-dialog-footer{line-height: 50px; text-align: right;}

使用:

    
      
你确定要删除选中的图书吗?
...

 

九、自定义alert,全局函数使用

参考链接:

https://www.jb51.net/article/159958.htm

vue.extend():

项目实战【vue,react,微信小程序】(1707B)_第4张图片

https://cn.vuejs.org/v2/api/#Vue-extend

 

Vue.extend()  参数是一个vue组件,使用脚手架开发时即.vue的文件,返回值是一个构造函数,这个构造函数使用new创建一个组件实例

项目实战【vue,react,微信小程序】(1707B)_第5张图片

项目实战【vue,react,微信小程序】(1707B)_第6张图片

 

Alert.vue:





index.js:

import Vue from 'vue'
import Alert from './Alert'

const AlertConstructor = Vue.extend(Alert)

const AlertFun = (options) => {
  let instance = new AlertConstructor({data: options}).$mount()
  document.body.appendChild(instance.$el)
}

export default AlertFun

vue入口函数在原型链上添加函数:

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'

import Alert from './components/Alert/index.js'

Vue.prototype.$MyAlert = Alert

new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

在组件里使用:

this.$MyAlert({title: '标题', message: '请选择要删除的图书~'})

在拦截器里使用:

import MyAlert from '../components/Alert'

axios.defaults.baseURL = 'http://localhost:85'

axios.interceptors.response.use((res) => {
  if (res.data.code === 400) {
    MyAlert({title: '标题', message: res.data.message})
  }
  return res
})

十、瀑布流

项目实战【vue,react,微信小程序】(1707B)_第7张图片

Waterfall.vue:





css:

.m-waterfall{position: relative; flex:1; overflow-y: auto;overflow-x: hidden; background: #eeeeee;}
.m-waterfall-item-wrap{display: inline-block;position: absolute; width: 50%;padding: 10px;box-sizing: border-box;vertical-align: top;}
.m-waterfall-item-wrap:last-child{margin: 0 0 50px 0;}
.m-waterfall-item{border-radius: 10px;}
.m-waterfall-img{width: 100%; border-top-left-radius: 10px;border-top-right-radius: 10px;}
.m-waterfall-info{margin: -4px 0 0;padding: 5px; height: 100px;background: #ffffff;border-bottom-right-radius: 10px;border-bottom-left-radius: 10px;}
.m-waterfall-end{position: fixed;width: 100%;line-height: 50px; bottom: 0; text-align: center;color: #aaaaaa;}

mock数据:

const news = Mock.mock({
	'list|500': [{
		'id|+1': 1,
		'name': '@cname',
		//'image': Mock.Random.image(null, '#ff0000', '#ffff00', 'hello'),
		'image': '@image()',
		'title': '@ctitle',
		'paragraph': '@cparagraph',
		'datetime': '@datetime'
	}]
}).list

分页+搜索接口:

app.get('/api/news', (req, res) => {
  let { page, size, search = '' } = req.query
  let newsSearchResult = news.filter(item => item.name.includes(search))
  let start = (page - 1) * size
  let end = start + size * 1
  res.send({
    code: 200,
    data: newsSearchResult.slice(start, end),
    message: '新闻'
  })
})

十一、reduce和immutable.js

Immutable Data 就是一旦创建,就不能再被更改的数据。对 Immutable 对象的任何修改或添加删除操作都会返回一个新的 Immutable 对象。Immutable 实现的原理是 Persistent Data Structure(持久化数据结构),也就是使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时为了避免 deepCopy 把所有节点都复制一遍带来的性能损耗,Immutable 使用了Structural Sharing(结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。请看下面动画:

项目实战【vue,react,微信小程序】(1707B)_第8张图片

1. 降低 Mutable 带来的复杂度

2. 节省内存空间

3. Undo/Redo,Copy/Paste,随意穿越!

4. 拥抱函数式编程

不要修改 state:

https://www.redux.org.cn/docs/basics/Reducers.html

https://segmentfault.com/a/1190000017294051

immutable官网:

https://immutable-js.github.io/immutable-js/

为啥要使用immutable:

http://yunlaiwu.github.io/blog/2016/12/01/react+redux+immutablejs/#2

简介:

Facebook 工程师 Lee Byron 花费 3 年时间打造!

https://www.jianshu.com/p/0fa8c7456c15

 

import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import { fromJS } from 'immutable'

const defaultState = fromJS({
  listAll: [],
  currentId: 0,
  myBook: []
})

const reducer = (state = defaultState, action) => {
  switch (action.type) {
    case 'SET_STATE':
      // let newState = JSON.parse(JSON.stringify(state))
      // newState[action.key] = action.value
      //state是一个immutable对象,调用setIn方法并不会修改state的值,因为state是immutable对象
      //newState是基于state和action创建出来的新immutable对象,这个创建过程并不是深拷贝,深拷贝性能很低
      //这个创建过程会共享没有改变的部分,避免深拷贝把所有节点都复制一遍带来的性能损耗
      //对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享
      let newState = state.setIn(action.key, fromJS(action.value))
      console.log(state.toJS())
      console.log(newState.toJS())
      return newState
    default: 
      return state
  }
}

const store = createStore(reducer, applyMiddleware(thunk))

store.subscribe(() => {
  //console.log(store.getState().toJS())
})

export default store
const mapStateToProps = (state) => {
  state = state.toJS()
  return {
    navList: state.navList,
    currentId: state.currentId,
    currentList: state.currentList
  }
}

const mapDispatchToProps = (dispatch) => {
  return ({
    setState(key, value) {
      dispatch({ type: 'SET_STATE', key, value })
    }
  })
}

export default connect(mapStateToProps, mapDispatchToProps)(List)

十二、使用immutable实现对象深拷贝








  

项目实战【vue,react,微信小程序】(1707B)_第9张图片

 

 

十三、路由懒加载

import React, { Component, Suspense, lazy } from 'react'
import { Switch, Route } from 'react-router-dom'
import Header from '../components/Header'
import Footer from '../components/Footer'
import Home from './Home'
//import MyBook from './MyBook'  //无懒加载
import Me from './Me'
//const MyBook = lazy(() => import('./MyBook'))  //有懒加载
import Loading from '../components/Loading'

//懒加载延时1
// const MyBook = lazy(async () => {
//   return await new Promise((resolve, reject) => {
//     setTimeout(() => {
//       resolve(import('./MyBook'))
//     }, 500)
//   })
// })

//懒加载延时2
const MyBook = lazy(async () => {
  let component
  await new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(import('./MyBook'))
    }, 500)
  }).then(res => {
    component = res
  })

  return component
})

export default class Index extends Component {
  render() {
    return (
      
}>
) } }

十四、小程序自定义对话框组件

dialog.js:

// components/dialog/dialog.js
Component({
  options: {
    styleIsolation: 'apply-shared', //isolatiion apply-shared shared
    multipleSlots: true
  },
  /**
   * 组件的属性列表
   */
  properties: {
    visible: Boolean,
    title: String
  },

  /**
   * 组件的初始数据
   */
  data: {

  },

  /**
   * 组件的方法列表
   */
  methods: {
    //小程序阻止遮罩层下的页面滚动
    handleMove(e) {

    }
  }
})

dialog.wxml:

除 bind 外,也可以用 catch 来绑定事件。与 bind 不同, catch 会阻止事件向上冒泡。



  
    {{title}}
    
      
    
    
      
    
  

dialog.wxss:

/* components/dialog/dialog.wxss */
.m-dialog-wrap{display: none; position: fixed;top: 0;left: 0;right: 0;bottom: 0;background: rgba(0, 0, 0, 0.5);z-index: 99;}
.m-dialog-wrap.active{display: flex;}
.m-dialog{display: flex;flex-direction: column; margin: auto;padding: 10rpx; min-width: 600rpx;min-height: 400rpx;background: #ffffff;border-radius: 10rpx;}
.m-dialog-header{height: 80rpx;font-weight: bold;}
.m-dialog-content{flex: 1;}
.m-dialog-footer{height: 80rpx;text-align: right;}



使用dialog组件:

  
    
      
        -
        
        +
      
    
    
      
      
    
  

 

十五、小程序案例

 

 

 

 

 

 

 

 

 

 

github源代码:

https://github.com/baweireact/m-apps/tree/master/m-app-1707B

 

 

 

 

 

 

 

 

你可能感兴趣的:(web前端)