12.弹出消息

110 阅读1分钟

1.使用css module

需要将样式文件命名为xxx.module.ooo

xxx为文件名

ooo为样式文件后缀名,可以是cssless

2.得到组件渲染的Dom

  /**
    获取某个组件渲染的Dom根元素
  */
function getComponentRootDom(comp, props){
  const vm = new Vue({
    render: h => h(comp, {props})
  })
  vm.$mount();
  return vm.$el;
}

3.扩展vue实例

扩展vue实例

4.ref

<template>
	<div>
    <p ref="para">some paragraph</p>
    <ChildComp ref="comp" />
    <button @click="handleClick">查看所有引用</button>
  </div>
</template>

<script>
  import ChildComp from "./ChildComp"
	export default {
    components:{
      ChildComp
    },
    methods:{
      handleClick(){
        // 获取持有的所有引用
        console.log(this.$refs);
        /*
        {
        	para: p元素(原生DOM),
        	comp: ChildComp的组件实例
        }
        */
      }
    }
  }
</script>

通过ref可以直接操作dom元素,甚至可能直接改动子组件,这些都不符合vue的设计理念。

除非迫不得已,否则不要使用ref

其实这里就是拿子组件的,从父组件拿组件,这里还要通过 refs来拿,很麻烦。iOS里面可以直接拿,用vue框架,就要受到框架的限制。

总结

前面几点知识都是为了解决一个问题就是我想弹出一个消息,我只想调一个方法,你就应该给我弹出,而不是想vue组件这种麻烦的操作,导入组件,注册组件,再在点击的时候做很多操作。我希望的是想要弹出的时候调用组件的一个方法,首先是所有的组件都能调用的方法就需要扩展vue实例方法。其次我们现在先通过dom操作给现在的组件添加一些东西,那我们就要先拿到组件的dom元素,就可以通过得到组件渲染的Dom 来拿到,拿到后就可以设置他dom元素的innerHTML设置一些子元素。还有一个问题就是我们在那弹这个弹框的问题,如果我们想在当前组件的子组件内部弹,vue无法直接拿到子组件,这里只能在通过ref来拿到子组件再来调弹框的方法。 最后开启css Moudle是为了解决css类名冲突的问题。

使用的代码

<template>
  <div class="home-container" ref="container">
    <h1>首页</h1>
    <button @click="handleClick">Click</button>
  </div>
</template>

<script>
export default {
  methods: {
    handleClick() {
      // this.$sayHello();
      this.$showMessage({
        content: "评论成功",
        type: "success",
        container: this.$refs.container,
        callback: function() {
          console.log("完成!!!");
        },
      });
    },
  },
};
</script>

<style scoped>
.home-container {
  background: lightblue;
  width: 300px;
  height: 500px;
  border: 1px solid;
  margin: 50px auto;
}
</style>

showMessage.js 的方法

import getComponentRootDom from "./getComponentRootDom";
import Icon from "@/components/Icon";
import styles from "./showMessage.module.less";

/**
 * 弹出消息
 * @param {String} content 消息内容
 * @param {String} type 消息类型  info  error  success  warn
 * @param {Number} duration 多久后消失
 * @param {HTMLElement} container 容器,消息会显示到该容器的正中;如果不传,则显示到页面正中
 */
export default function(options = {}) {
  const content = options.content || "";
  const type = options.type || "info";
  const duration = options.duration || 2000;
  const container = options.container || document.body;
  // 创建消息元素
  const div = document.createElement("div");
  const iconDom = getComponentRootDom(Icon, {
    type,
  });
  div.innerHTML = `<span class="${styles.icon}">${iconDom.outerHTML}</span><div>${content}</div>`;
  // 设置样式
  const typeClassName = styles[`message-${type}`]; //类型样式名
  div.className = `${styles.message} ${typeClassName}`;
  // 将div加入到容器中

  // 容器的position是否改动过
  if (getComputedStyle(container).position === "static") {
    container.style.position = "relative";
  }
  container.appendChild(div);
  // 浏览器强行渲染
  div.clientHeight; // 导致reflow

  // 回归到正常位置
  div.style.opacity = 1;
  div.style.transform = `translate(-50%, -50%)`;

  // 等一段时间,消失
  setTimeout(() => {
    div.style.opacity = 0;
    div.style.transform = `translate(-50%, -50%) translateY(-25px)`;
    div.addEventListener(
      "transitionend",
      function() {
        div.remove();
        // 运行回调函数
        options.callback && options.callback();
      },
      { once: true }
    );
  }, duration);
}