te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>javascript - Access class function in Web Component from inline Element - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Access class function in Web Component from inline Element - Stack Overflow

programmeradmin3浏览0评论

I want to execute a defined class function from an Element inside my Web Component:

customElements.define('first-ponent', class FirstComponent extends HTMLElement {
    constructor() {
        super();
     }

     log() {
        console.log('Well Done!')
     }

     connectedCallback() {
        this.innerHTML = '<button onclick="log()">Do it</button>'
     }
});

State right now: ReferenceError: log is not defined

I want to execute a defined class function from an Element inside my Web Component:

customElements.define('first-ponent', class FirstComponent extends HTMLElement {
    constructor() {
        super();
     }

     log() {
        console.log('Well Done!')
     }

     connectedCallback() {
        this.innerHTML = '<button onclick="log()">Do it</button>'
     }
});

State right now: ReferenceError: log is not defined

Share Improve this question edited Sep 18, 2019 at 23:19 Supersharp 31.2k11 gold badges101 silver badges147 bronze badges asked Dec 28, 2018 at 19:43 FabianFabian 1291 gold badge3 silver badges9 bronze badges
Add a ment  | 

5 Answers 5

Reset to default 10

With parentElement, or closest()

In order to call the log() method of the custom element, you'll have to get a reference on it.

In your example, the custom element is the parent element of the <button> element, so you should call the parentElement property of the button as already stated by @Smankusors:

<button onclick="this.parentElement.log()>Do it</button>

With getRootNode()

Alternately, in a more plex DOM tree, and if a Shadow DOM is used, you can use getRootNode() bined with host to get the custom element reference.

customElements.define('first-ponent', class FirstComponent extends HTMLElement {
     log() {
        console.log('Well Done!')
     }

     connectedCallback() {
        this.attachShadow({mode: 'open'})
            .innerHTML = '<button onclick="this.getRootNode().host.log()">Do it</button>'
     }
})
<first-ponent></first-ponent>


With a unique identifier

You can also call the custom element by its id property (if it has one) :

customElements.define('first-ponent', class FirstComponent extends HTMLElement {
     log() {
        console.log('Well Done!')
     }

     connectedCallback() {
        if (!this.id)
            this.id = "_id"
        this.innerHTML = `<button onclick="${this.id}.log()">Do it</button>`
     }
})
<first-ponent></first-ponent>


With handleEvent()

For security reasons, you can avoid inline script and implement the handleEvent() method, then call inside it a specific method depending on some criterions :

customElements.define('first-ponent', class FirstComponent extends HTMLElement {
    log() {
        console.log('Well Done!')
    }
     
    handleEvent(ev) {
        if (ev.target.innerText == 'Do it')
            this.log()
    }

    connectedCallback() {
        this.innerHTML = '<button>Do it</button>'
        this.addEventListener('click', this)
    }
})
<first-ponent></first-ponent>

That shouldn't be log(), but this.log(), because that log function scope is only that element, not in window scope, so your code should be

customElements.define('first-ponent', class FirstComponent extends HTMLElement {
    constructor() {
        super();
     }

     log() {
        console.log('Well Done!')
     }

     connectedCallback()
        this.innerHTML = '<button onclick="this.parentElement.log()">Do it</button>'
     }
});

-- EDIT -- Sorry, my mistake, I just saw that you added button inside custom element, well... It should be this.parentElement.log() if you still want to prefer inline

Since the DOM and its elements does not have any knowledge of the scope it lives in, just setting the value of the innerHTML won't work since log does not exist on window which is the DOM scope. Hence this, it's best practice to create the element and append it to the Shadow Dom of the custom element and at the same time add the eventListener to the button.

customElements.define('first-ponent', class FirstComponent extends HTMLElement {
    constructor() {
        super();
     }

     log() {
        console.log('Well Done!')
     }

     connectedCallback() { // This parentheses was also missing
         var shadow = this.attachShadow({mode: 'open'});
         const button = document.createElement("button");
         button.textContent = 'Do it!';
         button.addEventListener('click', () => this.log());
         shadow.appendChild(button);
     }
});
<first-ponent id="ponent"></first-ponent>

You should - for many reasons - stop using inline event listeners. Instead, use addEventListener - in this case in the connectedCallback.

customElements.define('first-element', class FirstElement extends HTMLElement {
    constructor() {
        super();
     }

     log() {
        console.log('Well Done!')
     }

     connectedCallback() {
        const btn = document.createElement('button');
        btn.textContent = 'Do it!';
        btn.type = 'button'; // otherwise it's type=submit
        btn.addEventListener('click', this.log);
        this.appendChild(btn);
     }
});
<first-element></first-element>

Here's my approach using template literals and window properties.

By using template literals you get the scope you want, but the onclick event still needs access to your method. I guess using window is the only way to share something from outer scope for the event in this case. Since the event takes in string type, I can just make it call window and some unique property name where the shared method lives in.

customElements.define('first-ponent', class FirstComponent extends HTMLElement {
   log() {
      console.log('Well Done!')
   }

   bind(callback) {
     if (!callback) return '';
     const name = 'generate_random_name';
     window[name] = callback;
     return `window.${name}();`;
   }

   connectedCallback() {
      this.innerHTML = `<button onclick=${this.bind(() => this.log())}>Do it</button>`
   }
});
<first-ponent></first-ponent>

To go a little bit further, we can also get rid of the bind method by using a tagged template literal. This allows us to manipulate the template string and it's dynamic values before they get rendered. Naming the tag to "html" is useful because it enables html's syntax highlighting.

function html(strings, ...values) {
  let str = '';
  strings.forEach((string, index) => {
    const value = values[index];
    if (typeof value === 'function') {
      const callback = value;
      const name = 'generate_random_name';
      window[name] = callback;
      str += string + `window.${name}();`;
    } else {
      str += string
    }
  });
  return str;
}

customElements.define('first-ponent', class FirstComponent extends HTMLElement {
  log() {
    console.log('Well Done!')
  }

  connectedCallback() {
    this.innerHTML = html`<button onclick=${() => this.log()}>Do it</button>`
  }
});
<first-ponent></first-ponent>

发布评论

评论列表(0)

  1. 暂无评论