• 手把手实现图片预览插件(三)


    因为项目需要,之前封装了一个图片点击预览的全局组件。这次我们尝试将它封装成一个插件。通过命令式的方式来达到点击预览的效果。

    在封装插件之前。我们要对vue的插件机制有个基本了解。vue的插件的核心是use方法。

    其实就是在Vue类上添加一个use方法,这个方法看传入第一个参数是否是函数,如果是函数则直接执行,如果是对象,就看是否有install方法,然后执行install方法,执行的时候把Vue类传入,同时把用户传入的option也传入

    1. Vue.use = function (plugin) {
    2. // 忽略已注册插件
    3. if (plugin.installed) {
    4. return
    5. }
    6. // 集合转数组,并去除第一个参数
    7. var args = toArray(arguments, 1);
    8. // 把this(即Vue)添加到数组的第一个参数中
    9. args.unshift(this);
    10. // 调用install方法
    11. if (typeof plugin.install === 'function') {
    12. plugin.install.apply(plugin, args);
    13. } else if (typeof plugin === 'function') {
    14. plugin.apply(null, args);
    15. }
    16. // 注册成功
    17. plugin.installed = true;
    18. return this;
    19. };

    而在install方法里。vue给我们提供了几种插件注册的方式

    (1) 全局minx混入  (2)全局组件注册 (3)给vue对象的原型添加该插件

    也就是说。插件调用的方式我们可以选择在全局组件的方式调用,也可以选择在vue原型上调用或者在minx混入里的某个时机去调用。

    说了那么多,我们开始自己的图片预览组件的开发

    (1) 我们在src下新建一个plugins文件夹。新建两个文件:

    prevImg.vue和index.js

    1. <template>
    2. <div class="prewImg-wrap" v-show="show">
    3. <div class="mask">div>
    4. <div class="action">
    5. <i class="el-icon-minus ic">i>
    6. <i class=" ic el-icon-plus">i>
    7. <i class=" ic el-icon-refresh-right">i>
    8. <i class=" ic el-icon-close" @click="close">i>
    9. div>
    10. <div class="img-wrap">
    11. <span v-if="loading" style="color:#fff">加载中...span>
    12. <img v-else ref="img" :src="url" alt="" class="pic"
    13. @load="handleImgLoad"
    14. @error="handleImgError">
    15. div>
    16. div>
    17. template>
    18. <script>
    19. export default {
    20. data(){
    21. return {
    22. show: false,
    23. loading:false,
    24. url:"https://s1.chu0.com/src/img/gif/30/30e530c90d674d26aa5afb35ab7eda84.gif"
    25. }
    26. },
    27. mounted(){
    28. this.loadImg()
    29. },
    30. watch:{
    31. url(val) {
    32. this.$nextTick(_ => {
    33. const $img = this.$refs.img;
    34. if (!$img.complete) {
    35. this.loading = true;
    36. }
    37. });
    38. }
    39. },
    40. methods:{
    41. close(){
    42. this.show=false
    43. },
    44. handleImgLoad(){
    45. this.loading=false
    46. },
    47. handleImgError(e){
    48. console.log("e-rror--",e)
    49. this.loading=false
    50. }
    51. }
    52. }
    53. script>
    54. <style scoped>
    55. .prewImg-wrap{
    56. position:fixed;
    57. left:0;
    58. top:0;
    59. width: 100%;
    60. height: 100%;;
    61. overflow: hidden;
    62. z-index:1;
    63. }
    64. .action{
    65. width: 200px;
    66. padding: 20px;
    67. position: absolute;
    68. right:10px;
    69. top:20px;
    70. color:#fff;
    71. z-index: 30;
    72. display: flex;
    73. justify-content: flex-end;
    74. }
    75. .ic{
    76. display: inline-block;
    77. margin-right: 10px;
    78. }
    79. .mask{
    80. background: rgba(0,0,0,0.6);
    81. position: absolute;
    82. top:0;
    83. left:0;
    84. z-index: 10;
    85. width: 100%;
    86. height: 100%;
    87. }
    88. .img-wrap{
    89. position: absolute;
    90. top:0;
    91. left:0;
    92. width: 100%;
    93. height: 100%;
    94. z-index:20;
    95. display: flex;
    96. justify-content: center;
    97. align-items: center;
    98. }
    99. .pic{
    100. max-height: 100%;
    101. max-width: 100%;
    102. }
    103. style>

    prevImg/index.js

    1. import PrevView from "./prewImg.vue"
    2. export default {
    3. install(Vue,options){
    4. let PrevVueConstructor= Vue.extend(PrevView)
    5. let instance= new PrevVueConstructor()
    6. document.body.appendChild(instance.$mount().$el);
    7. let prevObj={
    8. show(opts={text:"",url:""}){
    9. console.log("instance:",instance)
    10. instance.show=true
    11. instance.text=opts.text||""
    12. instance.url=opts.url||""
    13. },
    14. hide(){
    15. instance.show=false
    16. instance=null
    17. }
    18. }
    19. if(!Vue.$prevObj){
    20. Vue.$prevObj=prevObj
    21. }
    22. Vue.prototype.$prevImg = prevObj
    23. }
    24. }

    这个文件使我们这个插件的核心。首先我们通过vue.extend构造一个基于vue的构造函数,它类似于vue的实例。具备vue实例的所有属性和方法,和根vue实例不同的是,通过extend构造的子类只其data只能是一个函数。我们创建Vue实例时,都会有一个el选项,来指定实例的根节点,如果不写el选项,那组件就处于未挂载状态。Vue.extend 的作用,就是基于 Vue 构造器,创建一个‘ 子类 ',再配合$mount,就可以渲染组件,并且挂载到任意指定的节点上,比如body(这是单文件组件做不到的)

    在show方法中,console.log("instance:",instance)能看到它的具体结构。也正是因为它。所以我们可以直接访问到我们prewImg组件中data定义的数据。比如show,我们就可以通过操作show变量来控制open和hide方法直接让prevImg组件展示或隐藏。

    最后我们把这个prevImg对象挂载到vue的原型上。

    (2)main.js中引入 prevImg文件夹下的index.js

    1. import Vue from 'vue'
    2. import App from './App.vue'
    3. import "./directives/composImg"
    4. Vue.config.productionTip = false
    5. import ElementUI from 'element-ui';
    6. import 'element-ui/lib/theme-chalk/index.css';
    7. import prewImg from "./plugins/prewImg"
    8. Vue.use(ElementUI);
    9. Vue.use(prewImg)
    10. new Vue({
    11. render: h => h(App),
    12. }).$mount('#app')

    (3)具体使用

    1. <el-button @click="openPrev">打开预览el-button>
    2. <el-button @click="closePrve">关闭预览el-button>
    3. <script>
    4. export default{
    5. data(){
    6. return{
    7. restaurants: [],
    8. state1: '',
    9. url:"https://baj-dabanjiz-conf.oss-cn-hangzhou.aliyuncs.com/intelligent-design/image/20210730/middle/9bbeb6570f7b416b1bcbcc59a1b38635.jpg",
    10. url2:"https://fuss10.elemecdn.com/8/27/f01c15bb73e1ef3793e64e6b7bbccjpeg.jpeg"
    11. }
    12. },
    13. }
    14. methods:{
    15. openPrev(){
    16. this.$prevImg.show({url:this.url2})
    17. },
    18. closePrve(){
    19. this.$prevImg.hide()
    20. },
    21. }
    22. script>

  • 相关阅读:
    springboot+高校教室排课系统 毕业设计-附源码221556
    Servlet学生管理系统(萌新练手版)
    面试提问:为什么不建议在MySQL中使用 utf8?
    Java面试题及答案(2021年Java面试题大全带答案)
    从零学习Linux操作系统 第三十二部分 ansible中剧本的应用
    Dockerfile入门
    【Rust日报】2022-07-27 chrono 有了新的维护者
    深度学习基础之梯度下降
    Codeforces Round #832 (Div. 2) C. Swap Game
    如何在 Spring MVC 中处理表单提交
  • 原文地址:https://blog.csdn.net/baidu_41601048/article/details/126034029