Как штамповать шаблон в автономных пользовательских элементах с помощью vanilla js?
У меня есть пользовательский компонент, который просто показывает карту Таро. Перед пользовательским элементом я определил шаблон.
В подключенном обратном вызове моего wc я прикрепил сам шаблон к корню теней, а затем удалил его, клонировав его там же в корень теней. Я сделал это по 2 причинам:
- Я хочу, чтобы мой wc-компонент был автономным модулем; поэтому я хочу определить свой шаблон в том же месте, что и мой пользовательский элемент.
Кажется, это единственный способ удалить мой шаблон, чтобы сделать его пригодным для использования, не вставляя его в документ владельца.
var tmpl = ` <template id="tmpl"> <h1 class="tarot-title"><slot name="title">NEED TITLE</slot> </h1> <img src="${this.imageurl}" alt=""> <p><slot name="subtitle">NEED A SUBTITLE</slot></p> </template>`; class BdTarot extends HTMLElement { ...constructor etc... connectedCallback() { this._shadowRoot.innerHTML = tmpl; var _tmpl = this._shadowRoot.querySelector('#tmpl'); this._shadowRoot.appendChild(_tmpl.content.cloneNode(true)); } } customElements.define('bd-tarot', BdTarot);
Проблема, которую это создало, состоит в том, что у каждого компонента карты Таро, который я использую на своей странице, есть тот же самый шаблон, является дочерним, все с тем же идентификатором. Раз они в тени корней, имеет ли это значение? Хотя пахнет смешно...
Моя цель - просто попытаться понять, как все спецификации веб-компонентов сочетаются друг с другом. У меня вопрос, есть ли лучший способ сделать это, чтобы сохранить код моего компонента вместе и не ссылаться на документ владельца? Является ли спецификация шаблона в основном несовместимой с пользовательскими элементами, поскольку импорт html не принимается большинством поставщиков браузеров?
3 ответа
В двух словах: если вы используете шаблоны литералов, то вы не должны использовать <template>
элемент.
Вам не нужно дублировать шаблон, чтобы сохранить пользовательский элемент и коды шаблона вместе.
Вы можете просто заключить свой код в самозапускаемую функцию, чтобы быть уверенным, что переменная tmpl не будет переопределена.
(function () {
var tmpl = `
<h1 class="tarot-title"><slot name="title">NEED TITLE</slot></h1>
<img src="${this.imageurl}" alt="">
<p><slot name="subtitle">NEED A SUBTITLE</slot></p>`;
class BdTarot extends HTMLElement {
constructor() {
super()
this.attachShadow( { mode: 'open' } )
.innerHTML = tmpl;
}
}
customElements.define('bd-tarot', BdTarot);
})()
<bd-tarot>
<span slot="title">Queen</span>
</bd-tarot>
Если вы хотите сохранить локальную копию шаблона, вы можете скопировать ее в переменную экземпляра (this.tmpl
).
Попробуйте использовать приведенный ниже код, который добавляет пользовательскую аннотацию штампа в заголовок. Убедитесь, что размер пользовательского изображения штампа составляет 100*100 пикселей. В противном случае изображение штампа размыто или уменьшено.
const customStampTool = new Tools.RubberStampCreateTool(documentViewer);
const customImage = '../stamp.png';
// Register tool
instance.UI.registerTool({
toolName: stampToolName,
toolObject: customStampTool,
showPresets: true,
dataElement: 'customStampToolButton',
buttonImage: 'icon-tool-stamp-fill',
buttonName: 'customStampToolButton',
tooltip: 'Custom Stamp',
});
// Add tool button in header
instance.UI.setHeaderItems(header => {
header
.getHeader('toolbarGroup-Annotate')
.get('highlightToolGroupButton')
.insertBefore({
type: 'toolButton',
toolName: stampToolName,
onClick: async () => {
const imageSrc = customImage;
const canvasHeight = 140;
const canvasWidth = 160;
const imageSize = 80;
const stampAnnot = new Annotations.StampAnnotation();
stampAnnot.PageNumber = 1;
stampAnnot.X = 50;
stampAnnot.Y = 50;
stampAnnot.Width = canvasWidth;
stampAnnot.Height = canvasHeight;
// create a canvas in memory to draw your text to
const canvas = document.createElement('canvas');
canvas.width = canvasWidth;
canvas.height = canvasHeight;
const context = canvas.getContext('2d');
// Create an image object. This is not attached to the DOM and is not part of the page.
var image = new Image();
// When the image has loaded, draw it to the canvas and add the annot to annotation manager
image.onload = function () {
context.imageSmoothingEnabled = false;
context.drawImage(image, 40, 0, imageSize, imageSize);
context.font = "7pt Calibri";
context.fillText("Revise Name", 0, imageSize + 25);
context.fillText(userName, 0, imageSize + 30);
var currentdate = new Date();
var datetime = currentdate.getDate() + "/"
+ (currentdate.getMonth() + 1) + "/"
+ currentdate.getFullYear() + " "
+ currentdate.getHours() + ":"
+ currentdate.getMinutes() + ":"
+ currentdate.getSeconds();
context.fillText(datetime, 0, imageSize + 35);
// convert your canvas to a data URL
const dataURL = canvas.toDataURL();
// put your data URL here
stampAnnot.ImageData = dataURL;
annotationManager.addAnnotation(stampAnnot);
annotationManager.redrawAnnotation(stampAnnot);
}
// set width and height of the image and set the source.
image.width = imageSize;
image.height = imageSize;
image.src = imageSrc;
}
});
});
Хотя я согласен с утверждением @Supersharp о том, что литерал шаблона и шаблон не должны использоваться вместе, я думаю, что есть лучший способ управлять HTML-шаблоном компонента, несколько сочетая ваши подходы.
По сути, вместо того, чтобы иметь дело со строковым или шаблонным литералом, следует определить template
один раз и вводить его оттуда при создании экземпляра каждого компонента.
const template = document.createElement('template');
template.innerHTML = `
<h1 class="tarot-title">
<slot name="title">NEED TITLE</slot>
</h1>
<img src="${this.imageurl}" alt="">
<p>
<slot name="subtitle">NEED A SUBTITLE</slot>
</p>
`;
customElements.define('bd-tarot', class extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' })
.appendChild(template.content.cloneNode(true));
}
})();
Я писал здесь об этом, упомянув также мою собственную библиотеку, которая объединяет большую часть вышеуказанного шаблона в несколько API.