directive自定义指令把文案转html+输入功能

文案: 

"甲方(贷款人): 全称:$var<text_aasdrup06rc00> 法定代表人/负责人:$var<text_k2s9cffkhls00>地址:$var<text_6356yvx7oag00>\n\n乙方(借款人): 全称/姓名:(变量-姓名), 身份证号码/统一社会信用代码:(变量-身份证) 地址:$var<text_1g9bed61qp7k0>\n\n鉴于:\n\n甲方与乙方于  $var<date_3lday4c7pbs00>  日签订《贷款合同》,因还款纠纷,双方同意通过调解方式解决争议。\n经过友好协商,双方现已就贷款偿还、利息支付以及其他相关事项达成一致意见。\n调解协议条款:\n\n乙方确认尚欠甲方本金人民币  $var<money_etzhsw0n36o00>  元及至 $var<date_ispx8oc0ldk00>止的利息 $var<money_j784z1f8c8000> 元。\n\n乙方承诺按照以下分期还款计划偿还上述款项:\n\n第一期还款:$var<date_2j148ln3jzm00>前支付 $var<money_gmbbo2mnkrs00> 元;\n最后一期还款:$var<date_fueb9me7qxs00>前全部结清。\n若乙方按期足额偿还,则甲方同意免除逾期罚息和其他违约金;否则,甲方保留追索全部未偿债务及相关费用的权利。\n\n双方确认,本协议生效后,《贷款合同》中的争议即视为解决,任何一方不得再就已调解事项提起诉讼或仲裁,除非对方严重违反本协议。\n"
 
效果图:
 
vuex:
state
const state = {
  protocolData:[],//协议添加数据
}

export default state;
 
getters
/**
 * @description 全局的getters
 */
 const getters = {
  protocolData:(state)=>state.protocolData
}

export default getters;
mutations
 const mutations = {
  /**
   * [改变state的值]
   * @param  {[type]} state         [description]
   * @param  {[type]} options.key   [description]
   * @param  {[type]} options.value [description]
   * @return {[type]}               [description]
   */
  [TYPES.CHANGE_STATE]: (state, {
    key,
    value
  }) => {
    state[key] = value;
  },
}
export default mutations;
查看代码
 const actions = {

  /**
   * [changeStateValue 改变state的值]
   * @param  {[type]} options.commit [description]
   * @param  {[type]} options.key    [description]
   * @param  {[type]} options.value  [description]
   * @return {[type]}                [description]
   */
  changeStateValue({
    commit
  }, {
    key,
    value,
    callback
  }) {
    commit(TYPES.CHANGE_STATE, {
      key,
      value
    });
    if (callback) callback();
  },
}

export default actions;

 vue呈现窗口:

          <div
              class="custom_dom"
              v-insertDom="{value:item,readonly:false}"
            ></div>

css样式:

/deep/.custom_dom{
                .el-input{
                    .w(250) !important;
                    .el-input__inner{
                        // border: none !important;
                        border-left: none !important;
                        border-right: none !important;
                        border-top: none !important;
                        border-bottom: 1px solid #DCDFE6;
                        &:hover{
                            border-bottom: 1px solid #14DAAF; 
                        }
                    }
                    &.is_readonly{
                        .el-input__inner{
                            border-bottom: 1px solid #DCDFE6 !important;
                        }
                    }
                }
            }

 

vue自定义指令:

index.js
 
import insertDom from "./insertDom";

const install=function(Vue){
    Vue.directive('insertDom', insertDom)
}

if (window.Vue) {
    window['insertDom'] = insertDom
    Vue.use(install)
}
insertDom.install=install;
export default insertDom;

 

insertDom.js
import {
  verifyString,
  extractStringVariables
} from "@/utils";
import store from '@/store';
import {
  Input,
  DatePicker,
  Message
} from 'element-ui'
export default {
  inserted(el, binding, vnode) {
    const {
      value,
      readonly
    } = binding.value
    console.log(value);
    let _curStrArr = extractStringVariables(value);
    let _protocolData = store.getters && store.getters.protocolData;
    console.log(_curStrArr);
    let _modifiedStr = value;
    (_curStrArr || []).forEach(item => {
      _modifiedStr = _modifiedStr.replace(item.key, `--$--${item.id}--$--`);
    });
    let _domConArr = _modifiedStr.split('--$--');
    console.log(_domConArr);
    (_domConArr || []).forEach(item => {
      if (_protocolData.some(v => v.id == item)) {
        // let _childInput = document.createElement('input');
        // _childInput.setAttribute('type', 'text');
        // _childInput.setAttribute('placeholder', '请输入内容');
        // _childInput.setAttribute('id', item);
        // _childInput.addEventListener('change', (event) => {
        //     console.log(event.target.value);
        //     console.log(event.target.id);
        //     console.log(_protocolData, "_protocolData");
        //   });
        // el.appendChild(_childInput);
        // let instance = new Vue(Input).$mount();
        // 创建一个新的 Vue 实例,基于 Input 组件,并传入选项对象
        // 创建一个新的 Vue 实例,并传入选项对象  
        let _curDomObj=_protocolData.find(v=>v.id==item);
        let instance = null;
        if (item.indexOf("text_") > -1 || item.indexOf("money_") > -1) {
          instance = new Vue({
            //   el: document.createElement('div'), // 创建一个临时的 div 元素作为挂载点  
            render(h) {
              // 使用 render 函数渲染 Input 组件  
              return h(Input, {
                attrs: {
                  id: item, // 将 id 属性绑定到 Vue 实例的 data 中的 inputId
                },
                class:readonly?"is_readonly":"",
                props: {
                  placeholder: this.placeholder,
                  type: "text",
                  readonly:readonly,//是否仅读
                //   value: this.value,
                },
                model: {
                  value: this.value, // 将 value 属性绑定到 Vue 实例的 data 中的 value
                  callback: this.handleInput, // 绑定 input 事件到 handleInput 方法
                  expression: 'value',
                },
                on: {
                  // input: this.handleInput,
                  change: this.handleChange, // 添加 change 事件处理器
                },
              });
            },
            data() {
              return {
                // 在这里添加组件的属性  
                value: _curDomObj?.value?_curDomObj?.value:'',
                placeholder: readonly?"":item.indexOf("text_") > -1 ? '请输入内容' : '请输入金额',
              };
            },
            methods: {
              // 在这里添加组件的事件处理函数  
              handleInput(newValue) {
                this.value = newValue; // 更新 Vue 实例的 data 中的 value
                //   console.log('输入内容:', this.value);
              },
              handleChange(event) {
                console.log('值已更改:', event);
                if (item.indexOf("money_") > -1) {
                  let _regex = /^(\d+(\.\d{1,7})?)$/;
                  if (!_regex.test(event)) {
                    Message.error("请输入正确的金额格式");
                    this.value = "";
                    return
                  }
                }
                //   console.log(this.$el);
                let inputElement = this.$el.querySelector('input');
                let _tempId=inputElement.getAttribute('id');
                console.log('当前 input 的 id:',_tempId );
                let _tempProtocolData = store.getters && store.getters.protocolData;
                let _tempEditArr=(_tempProtocolData||[]).map(t=>{
                    if (t.id==_tempId) {
                        t.value=event;
                    }
                    return t;
                })
                store.dispatch("changeStateValue", {
                    key:"protocolData",
                    value:_tempEditArr
                });
              },
            },
            mounted() {
              // 通常不需要手动添加事件监听器,因为我们在 render 函数中已经做了这件事  
            },
            beforeDestroy() {
              // 通常不需要手动移除事件监听器,因为 Vue 会自动处理  
            },
          }).$mount(); // 手动挂载实例
        } else if (item.indexOf("date_") > -1) {
          instance = new Vue({
            //   el: document.createElement('div'), // 创建一个临时的 div 元素作为挂载点  
            render(h) {
              // 使用 render 函数渲染 Input 组件  
              return h(DatePicker, {
                attrs: {
                  id: item, // 将 id 属性绑定到 Vue 实例的 data 中的 inputId
                },
                class:readonly?"is_readonly":"",
                props: {
                  placeholder: this.placeholder,
                  type: "date",
                  valueFormat: "yyyy-MM-dd",
                  readonly:readonly
                  // value: this.value,
                },
                model: {
                  value: this.value, // 将 value 属性绑定到 Vue 实例的 data 中的 value
                  callback: this.handleDate, // 绑定 input 事件到 handleDate 方法
                  expression: 'value',
                },
                on: {
                  // input: this.handleDate,
                  change: this.handleChange, // 添加 change 事件处理器
                },
              });
            },
            data() {
              return {
                // 在这里添加组件的属性  
                value: _curDomObj?.value?_curDomObj?.value:'',
                placeholder: readonly?"":'请选择日期',
              };
            },
            methods: {
              // 在这里添加组件的事件处理函数  
              handleDate(newValue) {
                this.value = newValue; // 更新 Vue 实例的 data 中的 value
                //   console.log('输入内容:', this.value);
              },
              handleChange(event) {
                console.log('值已更改:', event);
                //   console.log(this.$el);
                let inputElement = this.$el.querySelector('input');
                let _tempId=inputElement.getAttribute('id');
                console.log('当前 input 的 id:',_tempId );
                let _tempProtocolData = store.getters && store.getters.protocolData;
                let _tempEditArr=(_tempProtocolData||[]).map(t=>{
                    if (t.id==_tempId) {
                        t.value=event;
                    }
                    return t;
                })
                store.dispatch("changeStateValue", {
                    key:"protocolData",
                    value:_tempEditArr
                });
              },
            },
            mounted() {
              // 通常不需要手动添加事件监听器,因为我们在 render 函数中已经做了这件事  
            },
            beforeDestroy() {
              // 通常不需要手动移除事件监听器,因为 Vue 会自动处理  
            },
          }).$mount(); // 手动挂载实例
        }

        // let parent = el.parentNode;
        // 将新创建的实例插入到指令所在的元素之后
        if (instance) {
          el.appendChild(instance.$el);
        }

        // parent.insertBefore(instance.$el, el.nextSibling);

      } else {
        el.appendChild(document.createTextNode(item));
      }
    });

    // const all_permission = '*:*:*'
    // const permissions = store.getters && store.getters.permisaction
    // // console.log(permissions,"permissions122");
    // // console.log(store.getters);
    // if (value && value instanceof Array && value.length > 0) {
    //   const permissionFlag = value

    //   const hasPermissions = permissions.some(permission => {
    //     return all_permission === permission || permissionFlag.includes(permission)
    //   })

    //   if (!hasPermissions) {
    //     el.parentNode && el.parentNode.removeChild(el)
    //   }
    // } else {
    //   throw new Error(`请设置操作权限标签值`)
    // }
  },
  unbind(el) {
    // 销毁组件实例
    if (el.firstChild && el.firstChild.$destroy) {
      el.firstChild.$destroy();
    }
  }
}

全局注册:

main.js
 import insertDom from "@/utils/insertDom";
Vue.use(insertDom);

utils工具:

/**
 * 校验字符串
 * @param {*} str 
 */
const verifyString=(str)=>{
  let regex =  /\$var<[a-zA-Z\d_]+>/;
  return regex.test(str)
}

/**
 * 抽取字符串变量
 * @param {*} str 
 */
const extractStringVariables=(str)=>{
    let _arr=[];
    // 创建一个正则表达式,用于匹配以 $var 开头,后面跟着一对尖括号 < 和 > 的字符串
    const regex = /\$var<([^>]+)>/g;
    // 使用 matchAll() 方法获取所有匹配项
    const matches = str.matchAll(regex);
    // 遍历匹配项并提取尖括号内的内容
    for (const match of matches) {
      _arr.push({
        id:match[1],
        key:match[0],
        value:"",
        index:match.index
      })
    }
    return _arr;
}

export {
  verifyString,
  extractStringVariables
}

 

posted @ 2024-04-11 16:46  春春&  阅读(1)  评论(0编辑  收藏  举报