【问题标题】:LWC1079 Expected root tag to be template, found metaLWC1079 预期的根标签是模板,找到元
【发布时间】:2020-11-25 04:03:56
【问题描述】:

在网上找到此代码作为开源代码,我一直在尝试将其转换为 LWC。代码采用 HTML、CSS 和 JS 格式。我正在 Visual Studio 中处理它,并且正在使用不接受 HTML 的 salesforce 扩展包,它需要标签,但我以前从未使用过模板标签。它也给了我错误,不允许元标记我不知道这个错误是什么。有人可以帮忙吗?错误在第 3 行

<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />

        <title>Maths Game</title>

        <link rel="stylesheet" href="mathGame.css" />
    </head>

    <body>
        <main>
            <div id="container">
                <p id="message" class="structure-elements"></p>
                <aside id="score" class="structure-elements">Score: <span>00</span></aside>

                <div id="calculation">
                    <section id="question" class="structure-elements"></section>
                    <p id="instruction" class="structure-elements">Click on the correct answer</p>
                    <ul id="choices" class="structure-elements">
                        <li></li>
                        <li></li>
                        <li></li>
                        <li></li>
                    </ul>
                </div>

                <button id="start-reset" class="structure-elements">Start Game</button>

                <aside id="time-remaining" class="structure-elements">Time remaining: <span>60</span> sec</aside>
            </div>

            <div id="game-over" class="structure-elements">
                <p>Game over!</p>
                <p>Your score is <span>00</span>.</p>
            </div>
        </main>

        <script src="mathGame.js"></script>
    </body>
</html>

**这是代码的 Javascript 部分

var Counter = {
    PlayingState: null,
    IsStoped: true,
    Score: 0,
    TimeRemaining: 0,
    FirstNumber: 0,
    SecondNumber: 0,
    CorrectAnswer: 0,
    CorrectPosition: 0,
    WrongAnswer: 0,
    AddContentToElement: function(selector, content)
    {
        document.querySelector(selector).innerHTML = content;
    },
    ChangeStyle: function(selector, property, value)
    {
        document.querySelector(selector).setAttribute(property, value);
    },
    Initialize: function(timeRemaining)
    {
        this.TimeRemaining = timeRemaining;
    },
    GenerateRandomNumber: function(multiplier)
    {
        return Math.round( Math.random() * multiplier ) + 1;
    },
    Refresh: function(selector, data)
    {
        document.querySelector(selector).innerText = (data < 10 ? "0" : "") + data;
    },
    LoopThroughElements: function()
    {
        var answers = [this.CorrectAnswer];

        for (var index = 1; index < 5; index++)
        {
            this.ChangeStyle("ul#choices > li:nth-of-type(" + index + ")", "style", "height:auto;");

            if (index !== this.CorrectPosition)
            {
                do
                {
                    this.WrongAnswer = this.GenerateRandomNumber(9) * this.GenerateRandomNumber(9);
                } while ( answers.indexOf(this.WrongAnswer) > -1 );

                this.AddContentToElement( "ul#choices > li:nth-of-type(" + index + ")", this.WrongAnswer );
                answers.push(this.WrongAnswer);
            }
        }
    },
    Launch: function()
    {
        this.IsStoped = false;
        this.Action();
        this.ChangeStyle("aside#time-remaining", "style", "visibility:visible;");
        this.ChangeStyle("#game-over", "style", "display:none;");
        this.ChangeStyle("ul#choices", "style", "pointer-events:initial; opacity:1;");
        this.ChangeStyle("button#start-reset", "style", "visibility:hidden;");
        this.AddContentToElement("button#start-reset", "Reset Game");
        this.Refresh("aside#time-remaining > span", this.TimeRemaining);
        this.GenerateQuestionAndAnswers();
    },
    GenerateQuestionAndAnswers: function()
    {
        this.FirstNumber = this.GenerateRandomNumber(9);
        this.SecondNumber = this.GenerateRandomNumber(9);
        this.CorrectAnswer = this.FirstNumber * this.SecondNumber;
        this.CorrectPosition = this.GenerateRandomNumber(3);
        this.ChangeStyle("section#question", "style", "height:auto;");
        this.AddContentToElement("section#question", this.FirstNumber + "x" + this.SecondNumber);
        this.AddContentToElement( "ul#choices > li:nth-of-type(" + this.CorrectPosition + ")", this.CorrectAnswer );
        this.LoopThroughElements();
    },
    Action: function()
    {
        Counter.PlayingState = setInterval( function()
        {
            Counter.TimeRemaining--;
            
            if (Counter.TimeRemaining <= 50)
            {
                Counter.ChangeStyle("button#start-reset", "style", "visibility:visible;");
            }

            if (Counter.TimeRemaining < 1)
            {
                Counter.Stop();
            }
            else
            {
                Counter.Refresh("aside#time-remaining > span", Counter.TimeRemaining);
            }
        }, 1000 );
    },
    EventListener: function(event)
    {
        if ( Number(event.currentTarget.innerText) === Number(Counter.CorrectAnswer) )
        {
            Counter.Score++;
            Counter.Refresh("aside#score > span", Counter.Score);
            Counter.GenerateQuestionAndAnswers();
            Counter.ChangeStyle("p#message", "style", "visibility:visible; background-color:#23A230;");
            Counter.AddContentToElement("p#message", "Correct");
        }
        else
        {
            if (Counter.Score >= 1)
            {
                Counter.Score -= 0.5;
                Counter.Refresh("aside#score > span", Counter.Score);
            }
            
            Counter.ChangeStyle("p#message", "style", "visibility:visible; background-color:#DE401A;");
            Counter.AddContentToElement("p#message", "Try again");
        }

        setTimeout( function()
        {
            Counter.ChangeStyle("p#message", "style", "visibility:hidden;");
        }, 1000 );
    },
    CheckClickOnRightAnswer: function()
    {
        for (var index = 1; index < 5; index++)
        {
            document.querySelector("ul#choices > li:nth-of-type(" + index + ")").removeEventListener("click", this.EventListener, false);
            document.querySelector("ul#choices > li:nth-of-type(" + index + ")").addEventListener("click", this.EventListener);
        }
    },
    Stop: function()
    {
        this.IsStoped = true;
        clearInterval(this.PlayingState);
        this.ChangeStyle("ul#choices", "style", "pointer-events:none; opacity:0.4;");
        this.ChangeStyle("aside#time-remaining", "style", "visibility:hidden;");
        this.ChangeStyle("div#game-over", "style", "display:block;");
        this.AddContentToElement("button#start-reset", "Start Game");
        this.AddContentToElement( "div#game-over > p:last-of-type > span", (this.Score !== "00" && this.Score < 10 ? "0" : "") + this.Score );
        this.AddContentToElement("aside#score > span", this.Score = "00");
    }
};


/*************************************************************************************************/
/* ************************************** CODE PRINCIPAL *************************************** */
/*************************************************************************************************/
document.addEventListener('DOMContentLoaded', function()
{
    document.getElementById("start-reset").addEventListener("click", function()
    {
        Counter.Initialize(60);
        Counter.IsStoped ? Counter.Launch() : Counter.Stop();
        Counter.CheckClickOnRightAnswer();
    });
});

【问题讨论】:

    标签: html visual-studio salesforce lwc


    【解决方案1】:

    使用 LWC,您无需编写整页应用程序,更不用说 &lt;html&gt;, &lt;head&gt;, &lt;body&gt;。您编写带有&lt;template&gt; 标签的小型可重用组件,它们可以放在不同的页面上。而且大多数时候您并不直接操作 HTML。您为 JS 变量设置值,框架重新呈现相关部分。简化表示和逻辑的拆分,并使逻辑可测试(是的,可以为 LWC 进行单元测试)。

    这些自定进度的培训可能会很方便:https://trailhead.salesforce.com/content/learn/modules/modern-javascript-developmenthttps://trailhead.salesforce.com/en/content/learn/modules/lightning-web-components-basics

    所以...如果您只是想让它在 Salesforce 中工作,您总是可以从中创建一个 Visualforce 页面,这最接近于整页应用程序。或者将你的东西作为静态资源上传,然后使用ligthning:container Aura 组件来加载它。它将作为 iframe 加载,但样式不会冲突,移植应用程序需要最少的 JS 知识,有时这就是方式。 更多的“专业人士”将尝试尽可能少地重写它。这件事严重地操纵了原始 HTML,这不完全是 LWC 方式,但它可以通过 lwc:dom="manual"

    如果您喜欢冒险 - 将其重写为 LWC。这远非完美,也不是完全重写,但应该会给你一些想法。

    html

    <template>
        <div>
            <lightning-layout multiple-rows="true">
                <lightning-layout-item size="6"><span class={messageStyle}>{message}</span></lightning-layout-item>
                <lightning-layout-item size="6">
                    Score: 
                    <lightning-formatted-number value={score} minimum-integer-digits="2"></lightning-formatted-number>
                </lightning-layout-item>
    
                <template if:false={isStopped}>
                    <lightning-layout-item size="12"><span class="question">{question}</span></lightning-layout-item>
                    <lightning-layout-item size="12">Click on the correct answer</lightning-layout-item>
    
                    <template for:each={answers} for:item="a">
                        <lightning-layout-item key={a.value} size="3">
                            <lightning-button label={a.value} value={a.value} variant="neutral" onclick={handleAnswerClick}></lightning-button>
                        </lightning-layout-item>
                    </template>
                </template>
    
                <lightning-layout-item size="6">
                    <template if:true={isButtonVisible}>
                        <lightning-button label={buttonLabel} variant={buttonVariant} onclick={handleButtonClick}></lightning-button>
                    </template>
                </lightning-layout-item>
                <lightning-layout-item size="6">
                    Time remaining: 
                    <lightning-formatted-number value={timeRemaining} minimum-integer-digits="2"></lightning-formatted-number>
                </lightning-layout-item>
            </lightning-layout>
        </div>
    </template>
    

    js

    import { track, LightningElement } from 'lwc';
    import { ShowToastEvent } from 'lightning/platformShowToastEvent'
    
    export default class Stack63257378 extends LightningElement {
        buttonLabel = 'Start Game';
        buttonVariant = 'success';
        isButtonVisible = true;
    
        message;
        messageStyle;
    
        firstNumber;
        secondNumber;
        @track answers = [];
    
        timeRemaining;
        score;
        isStopped = true;
    
        handleButtonClick(event){
            this.isStopped ? this.launch() : this.stop();
        }
    
        launch(){
            this.timeRemaining = 15; // 60
            this.isStopped = this.isButtonVisible = false;
            this.score = 0;
            let interval = setInterval(function (){
                --this.timeRemaining;
                if(this.timeRemaining <= 10){ // 50
                    this.isButtonVisible = true;
                    this.buttonLabel = 'Stop Game';
                    this.buttonVariant = 'destructive';
                }
                if(this.timeRemaining < 1){
                    clearInterval(interval);
                    this.stop();
                }
            }.bind(this),1000);
    
            this.generateQuestion();
        }
    
        handleAnswerClick(event){
            if(this.correctAnswer === event.target.value){
                ++this.score;
                this.generateQuestion();
                this.message = 'Correct';
                this.messageStyle = 'good';
            } else {
                if(this.score >= 1) {
                    this.score -= 0.5;
                }
                this.message = 'Try again';
                this.messageStyle = 'bad';
            }
        }
    
        stop(){
            this.answers = [];
            this.isStopped = true;
            this.buttonLabel = 'Start Game';
            this.buttonVariant = 'success';
            this.message = this.messageStyle = null;
            
            const event = new ShowToastEvent({
                title: 'Game over!',
                message: `Your score is ${this.score}`,
            });
            this.dispatchEvent(event);
        }
    
        generateQuestion(){
            this.firstNumber = this.getRandomNumber(9);
            this.secondNumber = this.getRandomNumber(9);
            this.correctAnswer = this.firstNumber * this.secondNumber;
            this.answers = [];
            let correctPosition = this.getRandomNumber(3);
            for(let i = 0; i < 4; ++i){
                let obj = {"i" : i, "value" : i === correctPosition ? this.correctAnswer : this.getRandomNumber(9) * this.getRandomNumber(9)};
                this.answers.push(obj);
            }
        }
    
        getRandomNumber(range){
            return Math.round( Math.random() * range ) + 1
        }
    
        get question(){
            return this.isStopped ? '' : `${this.firstNumber} x ${this.secondNumber}`;
        }
    }
    

    css

    .good {
        background-color:#23A230;
    }
    .bad {
        background-color:#DE401A;
    }
    .question {
        font-size: 24px;
    }
    button {
        width: 100%;
    }
    

    “meta-xml”(决定你可以在什么地方嵌入这个组件)

    <?xml version="1.0" encoding="UTF-8"?>
    <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
        <apiVersion>48.0</apiVersion>
        <isExposed>true</isExposed>
        <masterLabel>Math game</masterLabel>
        <description>https://stackoverflow.com/q/63257378/313628</description>
        <targets>
            <target>lightning__AppPage</target>
            <target>lightning__HomePage</target>
            <target>lightning__RecordPage</target>
        </targets>
    </LightningComponentBundle>
    

    【讨论】:

      猜你喜欢
      • 2014-10-03
      • 2012-06-23
      • 2023-01-07
      • 2015-07-08
      • 2011-02-19
      • 2012-06-24
      • 2018-07-30
      • 2017-09-19
      • 1970-01-01
      相关资源
      最近更新 更多