Vue - vue2 前端开发技术指南

自定义事件.sync 修饰符的使用

  • 在有些情况下,我们可能需要对一个 prop 进行“双向绑定”
// 子组件:
this.$emit('update:title', newTitle)
// 父组件
<text-document
  v-bind:title="doc.title"
  v-on:update:title="doc.title = $event"
>
</text-document>
// 为方便期间可以采用如下简写
<text-document v-bind:title.sync="doc.title"></text-document>

自定义组件的 v-model

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件。
输入控件可能会将 value attribute 用于不同的目的,model 选项可以用来避免这样的冲突

Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `
    <input
      type="checkbox"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
  `
})
/**
* 这里的 lovingVue 的值将会传入这个名为 checked 的 prop。
*  同时当 <base-checkbox> 触发一个 change 事件并附带一个新的值的时候,这个 lovingVue 的 property 将会被更新。
**/
<base-checkbox v-model="lovingVue"></base-checkbox>

侦听器监听值的变化执行副作用

 watch: {
    // 如果 `question` 发生改变,这个函数就会运行
    question: function (newQuestion, oldQuestion) {
      this.answer = 'Waiting for you to stop typing...'
      this.debouncedGetAnswer()
    }
  },
  • 直接侦听对象属性变化
<template>
  <div>
    <input v-model="user.name" placeholder="输入姓名">
  </div>
</template>

<script>
export default {
  data() {
    return {
      user: {
        name: '',
        age: 0
      }
    };
  },
  watch: {
    // 直接侦听 user 对象的 name 属性
    'user.name': {
      handler(newValue, oldValue) {
        console.log(`姓名从 ${oldValue} 变为 ${newValue}`);
        // 这里可以执行副作用操作,比如发送请求等
      },
      immediate: false // 是否在初始化时立即执行一次 handler
    }
  }
};
</script>
  • 侦听所有属性变化
<template>
  <div>
    <input v-model="user.name" placeholder="输入姓名">
    <input v-model.number="user.age" placeholder="输入年龄">
  </div>
</template>

<script>
export default {
  data() {
    return {
      user: {
        name: '',
        age: 0
      }
    };
  },
  watch: {
    user: {
      handler(newValue, oldValue) {
        console.log('用户信息发生了变化');
        // 执行副作用操作
      },
      deep: true, // 开启深度侦听
      immediate: false // 是否在初始化时立即执行一次 handler
    }
  }
};
</script>
  • 借助计算属性间接侦听
<template>
  <div>
    <input v-model="user.name" placeholder="输入姓名">
  </div>
</template>

<script>
export default {
  data() {
    return {
      user: {
        name: '',
        age: 0
      }
    };
  },
  computed: {
    // 计算属性返回要侦听的属性值
    userName() {
      return this.user.name;
    }
  },
  watch: {
    // 侦听计算属性
    userName(newValue, oldValue) {
      console.log(`姓名从 ${oldValue} 变为 ${newValue}`);
      // 执行副作用操作
    }
  }
};
</script>

使用props 传递数据给子组件

export default {
 props: ['initialCounter'],
 data: function () {
   return {
    counter: this.initialCounter
   }
 }
}

<baseInput :initialCounter="initialCounter" />

利用事件总线,将数据传递给多个监听此事件的组件中

可能出现的问题:此方式在组件初始化时,无法利用此方式进行数据传递,因为初始化时,有可能出现,在子组件还没有建立监听,已经从父组件触发了事件。
解决方案: 可以在触发事件的时候使用this.$nextTick 方法,保证子组件已经全部加载完毕,且已经进行了事件监听。

  1. 创建事件总线
// event-bus.js
import Vue from 'vue';
export const eventBus = new Vue();
  1. 监听事件 及移除监听
import { eventBus } from '@/utils/event-bus.js';
created() {
  eventBus.$on('eventName', (value) => {
    this.getStaticsData(value);
  });
},
beforeDestroy() {
  eventBus.$off('eventName');
}
  1. 触发事件
import { eventBus } from '@/utils/event-bus.js';
methods: {
  changeData(value){
     eventBus.$emit('eventName', value);
  }
}

利用provide 和 inject 进行数据传递

保持传递数据响应性的方式:

  • 传递对象给后代组件
  • 通过传递数据的计算属性到后代
  1. 祖先组件
  provide() {
    return {
      ids: this.sendConsignorIds
    };
  },

  1. 后代组件
inject: ['ids'],
created() {
  this.getStaticsData(this.ids.value);
},

vue2 异步更新队列

为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback)。
这样回调函数将在 DOM 更新完成后被调用。

// 使用回调
this.$nextTick(function () {
  console.log(this.$el.textContent) // => '已更新'
})

// 使用async,await 语法
methods: {
  updateMessage: async function () {
    this.message = '已更新'
    console.log(this.$el.textContent) // => '未更新'
    await this.$nextTick()
    console.log(this.$el.textContent) // => '已更新'
  }
}

vue2 调用子组件实例方法

<base-input ref="usernameInput"></base-input>
this.$refs.usernameInput.method()

vue2 动态组件

<template>
<div class="container page-container">
    <handle-tab v-model="applyType" :handles="types" @switch="searchDataList" />
    <keep-alive>
      <component :applyType="applyType" :key="applyType" :ref="`${currentTabComponent}Ref`"
        v-bind:is="currentTabComponent"></component>
    </keep-alive>
  </div>
</template>

<script>
// 铝锭发运审批                                                                                                            
import aluminumIngots from './components/aluminumIngots.vue'                                                               
// 铝液发运审批                                                                                                            
import moltenAluminum from './components/moltenAluminum.vue'    

export default {
  components: [
    HandleTab,
    aluminumIngots,
	moltenAluminum
  ],
  data() {
    return {
      componentCodeMap: {                                                                                                  
        [approveType.aluminumIngots.code]: 'aluminumIngots',                                                               
        [approveType.moltenAluminum.code]: 'moltenAluminum',                                                                                                               
       },                                                                                                                   
       currentTabComponent: 'aluminumIngots',                                                                               
       applyType: approveType.aluminumIngots.code,             
	};
  },
  watch: {                                                                                                                 
    // 根据tab组件返回的applyType值的变化匹配对应的组件                                                                    
    applyType: function (code) {                                                                                           
      this.currentTabComponent = this.componentCodeMap[code];                                                              
    }                                                                                                                      
  },   
  created() {                                                                                                                                              
    this.applyType = this.$route.query.applyType || this.applyType                                                         
  },                     
  async mounted() {                                                                                                        
     this.initTypes()                                                                                                                                                                                           
  }, 
  methods: {
    // 初始化页签
	initTypes() {
	  this.types = [
		{
		  code: approveType.aluminumIngots.code,
		  label: approveType.aluminumIngots.label
		},
		{
		  code: approveType.moltenAluminum.code,
		  label: approveType.moltenAluminum.label
		}      
	  ]
	},
	// 初始查询
	searchDataList() {
	  this.$nextTick(function () {
		this.$refs[`${this.currentTabComponent}Ref`].getDataList();
	  });
	},
 }
</script>           

vue2 混入

  1. 混入概念
  • 混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。
  • 所有混入对象的选项将被“混合”进入该组件本身的选项。
  1. 合并规则
  • 数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先
  • 同名钩子函数将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用。
  • 值为对象的选项,例如 methods、components 和 directives,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对。
  1. 在组件中使用混入
// 定义混入 mixin
export default {
  data() {
    return {
      editing: true
    }
  },
  computed: {},
  methods: {
    set(key, val) {
      this.listPageStore.commit(SET, { key, val })
    },
    merge(key, val) {
      this.listPageStore.commit(MERGE, { [key]: val })
    },
    validateFields(fields) {
      const state = this.listPageStore.state
      return validateFields(fields, state, key => {
        this.focus(state.keyMap[key])
      })
    }
  }
}

// 使用混入
import mixin from './mixin'
export default {
  mixins: [mixin],
}

vue2 响应式

  • vue2 响应式原理
  1. 当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,
    并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。
  2. 这些 getter/setter 对用户来说是不可见的,但是在内部它们让 Vue 能够追踪依赖,在 property 被访问和修改时通知变更。
  3. 每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。
    之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
  • Vue2 无法检测对象property 的添加或移除
  1. 由于 Vue 会在初始化实例时对 property 执行 getter/setter 转化,所以 property 必须在 data 对象上存在
    才能让 Vue 将它转换为响应式的
  2. 对于已经创建的实例,Vue 不允许动态添加根级别的响应式 property。但是,
    可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式 property
    this.$set(this.someObject,'b',2)
    
  3. 有时你可能需要为已有对象赋值多个新 property,比如使用 Object.assign() 或 _.extend()。但是,这样添加到对象上的
    新 property 不会触发更新。在这种情况下,你应该用原对象与要混合进去的对象的 property 一起创建一个新的对象。
    // 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
    this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
    
  • Vue2 不能检测数组的变化
  1. 当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
// 通过Vue.set 解决响应性问题
Vue.set(vm.items, indexOfItem, newValue)
// 通过重写的 Array.prototype.splice 解决
vm.items.splice(indexOfItem, 1, newValue)
  1. 当你修改数组的长度时,例如:vm.items.length = newLength
// 通过删除数组项实现
vm.items.splice(newLength)
  • 声明相应式property
    由于 Vue 不允许动态添加根级响应式 property,所以你必须在初始化实例前声明所有根级响应式 property,哪怕只是一个空值:
var vm = new Vue({
  data: {
    // 声明 message 为一个空值字符串
    message: ''
  },
  template: '<div>{{ message }}</div>'
})
// 之后设置 `message`
vm.message = 'Hello!'

vue2 利用vue-router重载当前页面

  • this.$router.go(0) 重刷当前页面
  • 重置路由实例来刷新当前页面,无需刷新整个页面,体验较好
// 保存当前路由实例
const currentRoute = this.$route;
// 跳转到一个空白路由
this.$router.replace({ path: '/blank' });
this.$nextTick(function() {
  // 跳转回当前路由
  this.$router.replace(currentRoute);
});

vue2 的生命周期函数

  • created: vue实例已创建,实例已完成对选项的处理,数据侦听、计算属性、方法、事件/侦听器的回调函数。
    然而,挂载阶段还没开始,且 $el property 目前尚不可用。

  • mounted: mounted 不会保证所有的子组件也都被挂载完成。如果你希望等到整个视图都渲染完毕再执行某些操作,
    可以在 mounted 内部使用 this.$nextTick:
    mounted: function () { this.$nextTick(function () { // 仅在整个视图都被渲染之后才会运行的代码 }) }
    若数据获取与Dom无关,则可以在created中调用异步函数获取数据,否则就必须在mounted中调用异步接口。

  • beforeDestroy: vue组件卸载前执行清理工作,比如定时器,事件监听等。

  • activated: vue组件激活时,在使用被keep-alive 组件缓存的组件激活时,可以执行的逻辑

vue2 样式覆写elementUI

.page-container {
  /deep/ .el-form-item {
    .el-input.custom-date-picker {
      max-width: 180px;
    }
  }
}

Vue2 手动生成dom元素节点

const h = this.$createElement;
h('p', null, '确定要作废此条出库单吗?'),

vue2 如何按需缓存特定路由组件

  • 通过路由meta信息控制
const routes = [
  {
    path: '/home',
    component: Home,
    meta: { keepAlive: true } // 表明该组件需要被缓存
  },
  {
    path: '/detail',
    component: Detail,
    meta: { keepAlive: false } // 表明该组件不需要被缓存
  }
]

<keep-alive>
  <router-view v-if="$route.meta.keepAlive"></router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"></router-view>
  • 通过组件名称(name)来控制, 在模版中使用include或exclude属性
<keep-alive include="Home,About">
  <!-- 只有组件名称是 Home 或者 About 的组件会被缓存 -->
  <router-view></router-view>
</keep-alive>
<keep-alive :include="cachedComponents">
  <router-view></router-view>
</keep-alive>

data() {
  return {
    cachedComponents: ['Home', 'About']
  }
}
  • 通过key强制更新组件
<keep-alive>
  <router-view :key="routeKey"></router-view>
</keep-alive>

computed: {
  routeKey() {
    // 当这个值变化时,组件会被重新渲染
    return this.$route.path
  }
}

ElementUI el-select 如何设置选中的选项label,与下拉选项的label不同

通过sloct-scope进行定制化显示: el-option 中的插槽显示下拉选项,:label选项则定义显示的label

<el-option v-for="item in codeList" :key="item.id" :label="item.code" :value="item.code">
 <template #default>
   <span>{{ `${item.code}(${item.name})`}}</span>
 </template>
</el-option>

vue2中使用加载图片

  1. 图片位于src/assets目录
<template>
  <div>
    <!-- 方法1:使用require -->
    <img :src="require('@/assets/logo.png')" alt="Logo">
    
    <!-- 方法2:在script中导入 -->
    <img :src="logoUrl" alt="Logo">
  </div>
</template>
<script>
export default {
  data() {
    return {
      // ES6导入(@是src目录的别名,由webpack配置)
      logoUrl: require('@/assets/logo.png')
    }
  }
}
</script>
  1. 在 CSS 中使用相对路径
<template>
  <div class="container"></div>
</template>

<style scoped>
.container {
  /* 假设图片与组件同级目录下的images文件夹 */
  background-image: url('./images/bg.png');
}
</style>
  1. 图片位于public目录
  • 位于public下的图片不会进行打包更改文件名称
  • 代码中使用/开头的绝对路径,开发环境相对于/public/,
  • 生产环境则会相对于服务根目录,如果是一个服务下面放置多个目录,使用绝对路径则会出现资源访问不到问题
<template>
  <div>
    <!-- 注意:路径以/开头,对应public目录 -->
    <img src="/images/logo.png" alt="Logo">
  </div>
</template>

vue2中引入svg icon组件

  1. 首先创建一个全局组件 SvgIcon.vue:
<template>
  <svg :class="svgClass" aria-hidden="true" v-bind="$attrs">
    <use :xlink:href="iconName" />
  </svg>
</template>

<script>
export default {
  name: 'SvgIcon',
  props: {
    iconClass: {
      type: String,
      required: true
    },
    className: {
      type: String,
      default: ''
    }
  },
  computed: {
    iconName() {
      return `#icon-${this.iconClass}`
    },
    svgClass() {
      if (this.className) {
        return `svg-icon ${this.className}`
      }
      return 'svg-icon'
    }
  }
}
</script>

<style scoped>
.svg-icon {
  width: 1em;
  height: 1em;
  vertical-align: -0.15em;
  fill: currentColor;
  overflow: hidden;
}
</style>
  1. 然后创建一个 svg 目录专门存放图标,并编写自动导入脚本:
// src/icons/index.js
import Vue from 'vue'
import SvgIcon from '@/components/SvgIcon.vue' // 路径根据实际情况调整

// 注册全局组件
Vue.component('svg-icon', SvgIcon)

// 自动导入所有svg文件
/**
*创建一个上下文环境,用于批量导入文件, 此上下文环境为函数
*第一个参数 './svg' 表示要搜索的目录
*第二个参数 false 表示不搜索子目录
*第三个参数 /\.svg$/ 是一个正则表达式,匹配所有以 .svg 结尾的文件
*/
const req = require.context('./svg', false, /\.svg$/)  

/**
* 定义一个函数,用于处理上下文环境
* requireContext.keys() 获取所有匹配到的文件路径数组
* 通过 map(requireContext) 导入所有这些文件
**/
const requireAll = requireContext => requireContext.keys().map(requireContext)

/** 执行导入操作,将所有 SVG 文件引入到项目中**/
requireAll(req)
  1. 在 main.js 中引入该脚本:
import './icons' // 引入svg图标
  1. 最后在项目中使用:
<svg-icon icon-class="your-icon-name" />

vuex 在vue2中的使用

  1. 创建store
  • src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
// 引入模块
import user from './modules/user'
import permission from './modules/permission'
// 引入 getters
import getters from './getters'

Vue.use(Vuex)
export default new Vuex.Store({
  modules: {
    user,
    permission,
  },
  getters
})

  • src/getters.js
export default {
  name: state => state.user.userName,
  btnList: state => state.permission.btnList,
  userInfo: state => state.user.originUserInfo
}
  • src/store/modules/user
const state = {
  loginAccount: '',
  userName: '',
};

const mutations = {
  RESET_STATE: state => {
    Object.assign(state, getDefaultState())
  },
  SET_TOKEN: (state, token) => {
    state.token = token
  },
  SET_USERINFO: (state, data) => {
    userInfoField.forEach(key => {
      state[key] = data[key] || getDefaultState()[key]
    })
    state.originUserInfo = data
    setUserInfo(data)
  },
};

const actions = {
  getInfo({ commit, state }) {
  },
  setUserInfo({ commit, state }) {
  },
};

export default {
  namespaced: true,
  state,
  mutations,
  actions
}
  1. 注入vue2实例
    在main.js 中挂载store
import Vue from 'vue'
import App from './App.vue'
import store from './store'

new Vue({
  store,  // 注入所有组件
  render: h => h(App)
}).$mount('#app')

  1. 在组件中使用
  • 在模版中访问
<template>
  <div>
    <p>Count: {{ $store.state.count }}</p>
    <p>User: {{ $store.state.user?.name }}</p>
  </div>
</template>
  • 在代码中访问
<script>
export default {
  methods: {
    increment() {
      this.$store.commit('INCREMENT')
    }
  }
}
</script>

  • 使用辅助函数简化代码
<script>
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'

export default {
  computed: {
    // 展开运算符混入
    ...mapState(['count']),
    ...mapGetters(['doubleCount'])
  },
  methods: {
    ...mapMutations(['INCREMENT']),
    ...mapActions(['login']),
    
    // 使用:
    handleClick() {
      this.INCREMENT()  // 直接调用
    }
  }
}
</script>

vue2 与 ElementUI中的字段验证

  1. 验证规则定义
rules: {
	actualPaymentAmount: [
	  { required: true, message: '请输入实收预付款金额', trigger: 'blur' },
	  // 通过正则表达式自定义验证
	  { pattern: /^\d+(\.\d+)?$/, message: '实收预付款金额必须是数字', trigger: 'blur' }
	],
	// 嵌套表单数组字段验证
	'shippingNoteMaterialList[0].shipmentQuantity': [
	  { required: true, message: '请输入发货数量', trigger: 'blur' },
	  { pattern: /^\d+(\.\d+)?$/, message: '发货数量必须是数字', trigger: 'blur' }
	],
	
	// 自定义验证规则, validator:指定验证函数
	username: [{ required: true, trigger: 'blur', validator: this.$rule.username }],
	password: [{ required: true, trigger: 'blur', validator: validatePassword }]
}
  1. 自定义验证函数
  • 在表单验证规则中,使用 validator 属性指定自定义验证函数
  • 自定义函数需要接收三个参数:rule(规则对象)、value(当前字段值)、callback(回调函数)
  • 验证通过时调用 callback(),不通过时调用 callback(new Error('错误信息'))
// 自定义验证函数 - 验证手机号
  const validatePhone = (rule, value, callback) => {
    const phoneReg = /^1[3-9]\d{9}$/;
    if (!value) {
      return callback(new Error('请输入手机号'));
    } else if (!phoneReg.test(value)) {
      return callback(new Error('请输入正确的手机号格式'));
    }
    callback(); // 验证通过
  };
  • 验证函数中的rule参数
    在 ElementUI 的自定义验证函数中,rule 参数包含了当前验证规则的完整配置信息,
    它主要用于在验证过程中获取规则定义的相关属性,帮助实现更灵活的验证逻辑。
    rule 是一个对象,包含以下主要属性(根据实际配置可能有所不同):
field:当前验证的字段名(与 prop 对应)
fullField:完整的字段路径(用于嵌套表单)
type:规则类型(如'string'、'number' 等,若未指定则为'string')
required:是否为必填项(布尔值)
message:默认错误提示信息
trigger:触发验证的时机(如 'blur'、'change')
其他自定义属性:在定义规则时可添加的额外属性

rule 参数的使用场景:

  • 复用验证函数:通过 rule 判断当前验证的字段,实现一个函数处理多个字段的验证
  • 读取规则配置:获取规则中定义的属性(如长度限制、自定义参数等)
  • 动态生成错误信息:结合 rule 中的信息自定义错误提示
data() {
  // 通用验证函数:同时处理手机号和邮箱验证
  const validateContact = (rule, value, callback) => {
    // 通过 rule.field 判断当前验证的字段
    if (rule.field === 'phone') {
      // 手机号验证
      const phoneReg = /^1[3-9]\d{9}$/;
      if (!value) {
        return callback(new Error(`请输入${rule.label || '手机号'}`));
      } else if (!phoneReg.test(value)) {
        return callback(new Error('请输入正确的手机号格式'));
      }
    } else if (rule.field === 'email') {
      // 邮箱验证
      const emailReg = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
      if (!value) {
        return callback(new Error(`请输入${rule.label || '邮箱'}`));
      } else if (!emailReg.test(value)) {
        return callback(new Error('请输入正确的邮箱格式'));
      }
    }
    callback();
  };

  // 带自定义参数的验证函数
  const validateRange = (rule, value, callback) => {
    // 从 rule 中获取自定义的 min 和 max 属性
    if (value < rule.min || value > rule.max) {
      return callback(new Error(`${rule.label}必须在${rule.min}-${rule.max}之间`));
    }
    callback();
  };

  return {
    form: {
      phone: '',
      email: '',
      age: ''
    },
    rules: {
      phone: [
        { 
          field: 'phone', 
          label: '手机号',  // 自定义属性,可通过 rule.label 获取
          validator: validateContact, 
          trigger: 'blur' 
        }
      ],
      email: [
        { 
          field: 'email', 
          label: '邮箱', 
          validator: validateContact, 
          trigger: 'blur' 
        }
      ],
      age: [
        { 
          type: 'number', 
          label: '年龄',
          min: 18,  // 自定义属性,年龄最小值
          max: 120, // 自定义属性,年龄最大值
          validator: validateRange, 
          trigger: 'blur' 
        }
      ]
    }
  };
}

vue2 插件编写

  • 编写验证函数插件
// src/utils/baseRule.js
const ruleInAll = {}
ruleInAll.install = function (Vue) {
  Vue.prototype.$rule = {
    // ip地址
    ip: (rule, value, callback) => {
      if (rule.required && !value) {
        callback(new Error('IP不能为空'))
      }
      if (value && !/^([0,1]?\d{1,2}|2([0-4][0-9]|5[0-5]))(\.([0,1]?\d{1,2}|2([0-4][0-9]|5[0-5]))){3}$/.test(value)) {
        callback(new Error('请输入有效的IP地址'))
      }
      callback()
    },
  }
}
export ruleInAll;
//main.js 引入
import Vue from 'vue'
import baseRule from '@/utils/baseRule'
Vue.use(baseRule)
// 项目表单验证规则中使用
  rules: {
	ipAddress: [{ required: true, validator: this.$rule.ip, trigger: 'blur' }]
  },

ElementUI中el-dialog 与父组件交互最佳实践

  1. 父组件中引入封装好的子组件dialog
<template>
    <ContractDialog ref="dialogRef" :row="currentRow" @close="closeDialog" />
</template>

<script>
import ContractDialog from '../components/contractDialog.vue'

 export default {
   components: {
    ContractDialog
  },
   data () {
     return {
	   currentRow: {},
	 }
   },
   methods: {
     // 打开弹窗
    openDialog(row) {
      this.currentRow = row; // 存储信息,并传递给弹窗组件
	  // 执行弹窗的初始化,及显示操作
      this.$nextTick(function() {
        this.$refs.dialogRef.openDialog();
      });
    },
    // 执行关闭弹窗后的回调操作
    closeDialog() {
	  // 设置已读
      this.readIt(this.currentRow);
    },
   },
   
 }
</script>
  1. 弹窗子组件的设计
  • 获取父组件传递的数据 props
  • 定义组件本身的状态(dialogVisible)以及显示数据(contractData)
  • 定义父组件调用的初始化方法(openDialog) 和 向父组件发送事件和传递数据的方法(closeDialog)
<template>
  <el-dialog title="合同变更" :visible.sync="dialogVisible" width="85%" :close-on-click-modal="false"
    :before-close="closeDialog">
	
  </el-dialog>
</template>
<script>
export default {
  props: ['row'],
  data() {
    return {
      loading: false,
      dialogVisible: false,
      contractData: {},
    }
  },
   methods: {
    openDialog() {
      // 显示弹窗
      this.dialogVisible = true;
	  // 获取数据
      this.getContractChange(this.row);
    },
    // 关闭弹窗
    closeDialog(done) {
      // 向父组件发送close事件,进行相应的处理
      this.$emit('close');
      // 关闭弹窗
      done();
    },
   },
 }
</script>

posted @ 2025-08-29 14:29  箫笛  阅读(19)  评论(0)    收藏  举报