1.使用css module
需要将样式文件命名为xxx.module.ooo
xxx为文件名
ooo为样式文件后缀名,可以是css、less
2.得到组件渲染的Dom
/**
获取某个组件渲染的Dom根元素
*/
function getComponentRootDom(comp, props){
const vm = new Vue({
render: h => h(comp, {props})
})
vm.$mount();
return vm.$el;
}
3.扩展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);
}