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


    目录

    一、transition过渡动画

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

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

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

    五、forEach

    六、vuex getters

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

    八、对话框组件

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

    十、瀑布流

    十一、reduce和immutable.js

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

    十三、路由懒加载

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

    十五、小程序案例

    github源代码:


    一、transition过渡动画

    过渡:

    <template>
      <div>
        <div>
          <router-link to="/index/home" class="m-nav-item">首页</router-link>
          <router-link to="/index/my_book" class="m-nav-item">书包</router-link>
          <router-link to="/index/news" class="m-nav-item">新闻</router-link>
        </div>
        <transition name="m-slide">
          <router-view class="m-router"></router-view>
        </transition>
      </div>
    </template>
    
    <script>
    export default {
      watch: {
        $route(to, from) {
          console.log(to);
        }
      },
      methods: {
    
      }
    };
    </script>
    
    <style>
    .m-router {
      position: absolute;
       100%;
    }
    /* 新路由的初始样式 */
    .m-slide-enter {
      transform: scale(2, 2) rotate(-5deg) translate(100%, 0);
      opacity: 0;
    }
    
    /* 新路由的目标样式 */
    .m-slide-enter-to {
      color: red!important;
    }
    
    /* 新路由动画 */
    .m-slide-enter-active {
      transition: all 1s ease-in-out;
    }
    
    /* 老路由目标样式 */
    .m-slide-leave-to {
      transform: translate(-100%, 0);
    }
    
    /* 老路由动画 */
    .m-slide-leave-active {
      transition: all 1s ease-in-out;
    }
    </style>

    动画:

    <template>
      <div>
        <div>
          <router-link to="/index/home" class="m-nav-item">首页</router-link>
          <router-link to="/index/my_book" class="m-nav-item">书包</router-link>
          <router-link to="/index/news" class="m-nav-item">新闻</router-link>
        </div>
        <transition name="m-slide">
          <router-view class="m-router"></router-view>
        </transition>
      </div>
    </template>
    
    <script>
    export default {
      watch: {
        $route(to, from) {
          console.log(to);
        }
      },
      methods: {
    
      }
    };
    </script>
    
    <style>
    .m-router {
      position: absolute;
       100%;
    }
    
    /* 新路由动画 */
    .m-slide-enter-active {
      animation: new-router 1s ease-in-out;
    }
    
    /* 老路由动画 */
    .m-slide-leave-active {
      animation: old-router 1s ease-in-out;
    }
    
    @keyframes new-router {
      0% {
        transform: scale(2, 2) rotate(-5deg) translate(100%, 0);
        opacity: 0;
      }
      50% {
        color: red;
      }
      100% {
    
      }
    }
    
    @keyframes old-router {
      0% {
        transform: translate(100px)
      }
      100% {
        transform: translate(-100%, 0);
      }
    }
    </style>

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

    使用immutable:

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <title>immutable.js实例</title>
      <style type="text/css">
      </style>
    </head>
    
    <body>
      <script src="https://cdn.bootcss.com/immutable/4.0.0-rc.12/immutable.js"></script>
      <script type="text/javascript">
        // 原来的写法
        var foo = { a: { b: 1 } };
        var bar = foo;
        bar.a.b = 2;
        console.log(foo.a.b);  // 打印 2
        console.log(foo === bar);  //  打印 true
    
        // 使用 immutable.js 后
        var foo = Immutable.fromJS({ a: { b: 1 } });
        var bar = foo.setIn(['a', 'b'], 2);   // 使用 setIn 赋值
        console.log(foo.getIn(['a', 'b']));  // 使用 getIn 取值,打印 1
        console.log(foo === bar);  //  打印 false     
        console.log(bar.getIn(['a', 'b']))  //2
        console.log(bar.toJS())  //转变成js对象
    
        let obj1 = Immutable.fromJS({
          a: {
            b: 1,
            c: [1, 2]
          }
        })
    
        let obj2 = Immutable.fromJS({
          a: {
            b: 1,
            c: [1, 2]
          }
        })
    
        //比较两个对象是否相等
        console.log(Immutable.is(obj1, obj2))
      </script>
    </body>
    
    </html>

     使用原生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

    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')
    
        <div v-for="item in list" :key="item.id" class="m-list-item">
          <div class="m-img-wrap">
            <img v-lazy="item.avatar" class="m-img">
          </div>
          <div class="m-info">
            {{item.title}}
          </div>
        </div>
    .m-list-item{display: flex;margin: 5px;}
    .m-img-wrap{display: flex;  122px;height: 150px;background: #dddddd;}
    .m-img{ 122px;height: 150px;}
    .m-img[lazy=loading]{margin: auto;  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')
    
        <div v-for="item in list" :key="item.id" class="m-list-item">
          <div class="m-img-wrap">
            <img v-lazy="item.avatar" class="m-img">
          </div>
          <div class="m-info">
            {{item.title}}
          </div>
        </div>
    .m-list-item{display: flex;margin: 5px;}
    .m-img-wrap{display: flex;  122px;height: 150px;background: #dddddd;}
    .m-img-wrap::before{content: '';margin: auto; 38px;height: 38px;background-image: url(./images/loading.png);animation: loading 1s linear infinite;}
    .m-img{position: absolute;  122px;height: 150px;}
    .m-img[lazy=loading]{margin: auto;  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);
    });

    六、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)
        }
      },

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

    <template>
      <div>
        <img :src="detail.avatar" />
        <div>
          {{detail.summary}}
        </div>
        <div>
          <button v-if="detail.is_in_my_book">已收藏</button>
          <button v-else @click="handleAdd(detail)">收藏</button>
        </div>
      </div>
    </template>
    
    <script>
    import Api from '../api'
    
    export default {
      data() {
        return {
          detail: {}
        };
      },
      methods: {
        handleAdd(detail) {
          detail.count = 1
          Api.add({
            book: detail
          }).then(res => {
            if(res.code === 200) {
              //this.detail.is_in_my_book = true   //不推荐的写法
              //this.$set(this.detail, 'is_in_my_book', true)   //推荐的写法
              //this.detail = {...this.detail, is_in_my_book: true} //推荐的写法
              this.detail = Object.assign({}, this.detail, {is_in_my_book: true})  //推荐的写法
            }
          })
        }
      },
      mounted() {
        let { id } = this.$route.params;
        Api.getDetail(`?id=${id}`).then(res => {
          if (res.code === 200) {
            this.detail = res.data;
          }
        });
      }
    };
    </script>
    
    <style>
    </style>

    参考链接:

    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:

    <template>
      <div class="m-dialog-wrap" :class="{active: visible}">
        <div class="m-dialog">
          <div class="m-dialog-title">{{title}}</div>
          <div class="m-dialog-content">
            <slot></slot>
          </div>
          <div class="m-dialog-footer">
            <slot name="footer"></slot>
          </div>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      props: ['visible', 'title']
    }
    </script>
    
    <style>
    
    </style>

    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- 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;}
    

    使用:

        <Dialog :visible="visible" title="提示">
          <div>你确定要删除选中的图书吗?</div>
          <div>...</div>
          <template v-slot:footer>
            <div>
              <button @click="handleHideDialog">取消</button>
              <button @click="handleDeleteSelected">确定</button>
            </div>
          </template>
        </Dialog>

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

    参考链接:

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

    vue.extend():

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

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

    Alert.vue:

    <template>
      <div class="m-dialog-wrap" :class="{active: visible}">
        <div class="m-dialog">
          <div class="m-dialog-title">{{title}}</div>
          <div class="m-dialog-content">
            {{message}}
          </div>
          <div class="m-dialog-footer">
            <button @click="handleHideDialog">确定</button>
          </div>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          title: '',
          message: '',
          visible: true
        }
      },
      methods: {
        handleHideDialog() {
          this.visible = false
        }
      }
    }
    </script>
    
    <style>
      
    </style>

    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
    })

    十、瀑布流

    Waterfall.vue:

    <template>
      <div class="m-news-wrap">
        <div class="m-news-serarch">
          <input type="text" placeholder="请输入关键词" v-model="search" @keyup.enter="handleSearch" />
        </div>
        <div class="m-waterfall js-waterfall" @scroll="handleScroll">
          <div id="m-waterfall-top"></div>
          <div>
            <div v-for="item in list" :key="item.id" class="m-waterfall-item-wrap js-waterfall-item-wrap">
              <div class="m-waterfall-item">
                <img :src="item.image" class="m-waterfall-img" :height="imageHeight(item.image)" />
                <div class="m-waterfall-info">{{item.id}} {{item.name}}</div>
              </div>
            </div>
          </div>
          <div class="m-waterfall-end">{{end}}</div>
        </div>
        <el-backtop target=".js-waterfall"></el-backtop>
      </div>
    </template>
    
    <script>
    import Api from "../api";
    
    let isUpdated = true;
    export default {
      data() {
        return {
          list: [],
          page: 1,
          search: "",
          end: ""
        };
      },
      methods: {
        handleScroll(e) {
          console.log(
            e.target.clientHeight,
            e.target.scrollTop,
            e.target.scrollHeight
          );
          let { scrollTop, clientHeight, scrollHeight } = e.target;
          if (
            scrollTop + clientHeight + 200 > scrollHeight &&
            isUpdated &&
            this.end === ""
          ) {
            this.page++;
            isUpdated = false;
            Api.news(`?page=${this.page}&size=10&search=${this.search}`).then(
              res => {
                if (res.code === 200) {
                  this.list = [...this.list, ...res.data];
                  if (res.data.length < 10) {
                    this.end = "我是有底线的~";
                  }
                }
              }
            );
          }
        },
        handleSearch() {
          document.getElementById("m-waterfall-top").scrollIntoView(true);
          Api.news(`?page=1&size=10&search=${this.search}`).then(res => {
            if (res.code === 200) {
              this.list = res.data;
              this.page = 1;
              this.end = "";
            }
          });
        },
        waterFall() {
          let items = document.getElementsByClassName("js-waterfall-item-wrap");
          items = Array.from(items);
          items[0].style.top = 0; //第一个元素
          items[0].style.left = 0;
          items[1].style.top = 0; //第二个元素
          items[1].style.left = "50%";
    
          let arr = [];
          arr.push(items[0].offsetHeight); //第一个元素
          arr.push(items[1].offsetHeight); //第二个元素
          for (let i = 2; i < items.length; i++) {
            let minHeight = arr[0];
            let index = 0;
            for (let j = 0; j < arr.length; j++) {
              if (minHeight > arr[j]) {
                minHeight = arr[j];
                index = j;
              }
            }
            items[i].style.top = arr[index] + "px";
            items[i].style.left = items[index].offsetLeft + "px";
            arr[index] = arr[index] + items[i].offsetHeight;
          }
        },
        imageHeight(url) {
          let size = url.slice(url.lastIndexOf("/") + 1).split("x");
          //真实宽度 / 真实高度 = 原始宽度  / 原始高度
          //真实高度 = 真实宽度 / 原始宽度 * 原始高度
          let height =
            ((window.document.body.clientWidth / 2 - 20) / size[0]) * size[1];
          return height;
        }
      },
      updated() {
        isUpdated = true;
        this.waterFall();
      },
      mounted() {
        Api.news("?page=1&size=10").then(res => {
          if (res.code === 200) {
            this.list = res.data;
          }
        });
      }
    };
    </script>
    
    <style>
    </style>

    css:

    .m-waterfall{position: relative; flex:1; overflow-y: auto;overflow-x: hidden; background: #eeeeee;}
    .m-waterfall-item-wrap{display: inline-block;position: absolute;  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{ 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; 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(结构共享),即如果对象树中一个节点发生变化,只修改这个节点和受它影响的父节点,其它节点则进行共享。请看下面动画:

    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实现对象深拷贝

    <!DOCTYPE html>
    <html>
    
    <head>
    </head>
    
    <body>
      <div>
        <script src="https://cdn.bootcss.com/immutable/4.0.0-rc.12/immutable.js"></script>
        <script>
          let obj = {
            a: 1,
            b: {
              c: '1'
            },
            fun() {
              console.log(1)
            },
            time: new Date(),
            d: undefined
          }
          //有兼容性问题,https://www.cnblogs.com/sweet-ice/p/10583192.html
          let objClone = JSON.parse(JSON.stringify(obj))
          console.log(objClone)
          //使用immutable可以深拷贝值为undefined、函数和日期的key
          let objClone2 = Immutable.fromJS(obj).toJS()
          console.log(objClone2)
          objClone2.a = 2
          console.log(obj.a)  //1
          console.log(objClone2.a)  //2
    
          
        </script>
      </div>
    
    
    </body>
    
    </html>

    十三、路由懒加载

    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 (
          <div className="m-wrap">
            <Header></Header>
            <Suspense fallback={<div className="m-main"><Loading lazyLoading={true}></Loading></div>}>
              <Switch>
                <Route path="/index/home" component={Home}></Route>
                <Route path="/index/my_book" component={MyBook}></Route>
                <Route path="/index/me" component={Me}></Route>
              </Switch>
            </Suspense>
            <Footer></Footer>
            <Loading></Loading>
          </div>
        )
      }
    }
    

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

    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 会阻止事件向上冒泡。

    <!--components/dialog/dialog.wxml-->
    <view class="m-dialog-wrap {{visible ? 'active' : ''}}" catch:touchmove="handleMove">
      <view class="m-dialog">
        <view class="m-dialog-header">{{title}}</view>
        <view class="m-dialog-content">
          <slot name="content"></slot>
        </view>
        <view class="m-dialog-footer">
          <slot name="footer"></slot>
        </view>
      </view>
    </view>
    

    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- 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组件:

      <dialog visible="{{visible}}" title="添加">
        <view slot="content" class="m-count-wrap">
          <view class="m-count">
            <text class="m-text-btn" bind:tap="handleSub">-</text>
            <input class="m-input" placeholder="请输入" value="{{item.count}}"></input>
            <text class="m-text-btn" bind:tap="handleAdd">+</text>
          </view>
        </view>
        <view slot="footer">
          <button size="mini" class="m-btn" bind:tap="handleHideDialog">取消</button>
          <button size="mini" class="m-btn" bind:tap="handleAddToMyBook">确定</button>
        </view>
      </dialog>

    十五、小程序案例

    github源代码:

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

  • 相关阅读:
    循环计时器
    在一个表格里,超过一定宽度字符串进行截取显示点点,鼠标移上去显示全
    判断单选框是否被选中
    美化的select下拉框
    js获取网页高度
    Bootstrap的使用。。。
    解决网站出现GET .woff 404 (Not Found)的问题
    Bootstrap 字体图标(Glyphicons)
    一个设置为display:none;的div,在用.height()方法获取不到它的高,获取到的高度为0.
    substring() slice() substr()的区别联系
  • 原文地址:https://www.cnblogs.com/xutongbao/p/14876303.html
Copyright © 2020-2023  润新知