且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

我对Sapper/Svelte有疑问

更新时间:2023-02-08 15:41:53

  1. Svelte将仅迭代类似数组的对象,因为不可能保证对象的行为一致-它抛出了各种边缘情况,这些情况***在应用程序级别解决.您可以使用标准的JavaScript惯用法来完成这种事情:

  {{#每个Object.values(info.attributes)as attr}}< p> {{attr.description}} ...</p>{{/每个}}<!-或者,如果您也需要密钥->{{#each Object.entries(info.attributes)as [key,value]}}< p> {{attr.description}} ...</p>{{/每个}} 

  1. 不知道直接的角度平移等效项,但是一种直接的i18n解决方案是在 preload 中获取一些JSON:

  preload({params,query}){返回fetch(`/i18n/$ {locale} .json`).then(r => r.json()).then(dict => {返回{dict};});} 

然后,您可以在模板中引用诸如 {{dict ["hello"]}} 之类的内容.一个更复杂的解决方案将仅加载当前页面所需的字符串,并缓存所有内容等,但是基本思想是相同的.

  1. 我想你可以这样做:

 //app/client.js(假设Sapper> = 0.7)从'./config/components.json'导入COMPONENTS;window.COMPONENTS =组件;//app/server.js从'./config/components.json'导入COMPONENTS;global.COMPONENTS =组件; 

虽然导入还不错!明确模块的依赖关系是有益的.

  1. 您可以在Webpack配置中使用 resolve.modules 字段: https://webpack.js.org/configuration/resolve/#resolve-modules

  2. 这是使用双向绑定的好地方:

  {{#每个Object.values(info.attributes)as attr}}< p> {{attr.description}}<输入bind:value = organization_name/></p>{{/每个}} 

  1. 是的, params 对象始终在您的页面中可用(不是嵌套组件,除非您向下传递prop,而是所有***组件,例如 routes/whatever/[slug]] .html )—因此您可以在模板中以 {{params.slug}} 引用它,或者在生命周期内使用钩子和方法在 this.get('params')中引用它.slug ,无论给定组件是否使用 preload .

I just started using Sapper (https://sapper.svelte.technology) for the first time. I really like it so far. One of the things I need it to do is show a list of the components available in my application and show information about them. Ideally have a way to change the way the component looks based on dynamic bindings on the page.

I have a few questions about using the framework.

First, I'll provide a snippet of my code, and then a screenshot:

[slug].html
-----------

<:Head>
<title>{{info.title}}</title>
</:Head>

<Layout page="{{slug}}">
    <h1>{{info.title}}</h1>

    <div class="content">
         <TopBar :organization_name />
    <br>
    <h3>Attributes</h3>
    {{#each Object.keys(info.attributes) as attribute}}
    <p>{{info.attributes[attribute].description}} <input type="text" on:keyup="updateComponent(this.value)" value="Org Name" /></p>
    {{/each}}
    </div>
</Layout>

<script>
import Layout from '../_components/components/Layout.html';
import TopBar from '../../_components/header/TopBar.html';

let COMPONENTS = require('../_config/components.json');

export default {
    components: {
        Layout, TopBar
    },

      methods: {
          updateComponent(value) {
            this.set({organization_name: value});
          }
      },

  data() {
      return {
        organization_name: 'Org Name'
      }
  },

  preload({ params, query }) {

    params['info'] = COMPONENTS.components[params.slug];

    return params;
  }

};
</script>

Now my questions:

  1. I notice I can't #each through my object. I have to loop through its keys. Would be nice if I could do something like this:

    {{#each info.attributes as attribute }}

    {{attribute.description}}

    {{/each}}

  2. Before Sapper, I would use Angular-translate module that could do translations on strings based on a given JSON file. Does anyone know if a Sapper/Svelte equivalent exists, or is that something I might need to come up with on my own?

  3. I'm not used to doing imports. I'm more use to dependency injection in Angular which looks a bit cleaner (no paths). Is there some way I can create a COMPONENTS constant that could be used throughout my files, or will I need to import a JSON file in every occurence that I need access to its data?

  4. As a follow-up to #3, I wonder if there is a way to better include files instead of having to rely on using ../.. to navigate through my folder structure? If I were to change the path of one of my files, my Terminal will complain and give errors which is nice, but still, I wonder if there is a better way to import my files.

  5. I know there has got to be a better way to implement what I implemented in my example. Basically, you see an input box beside an attribute, and if I make changes there, I am calling an updateComponent function which then does a this.set() in the current scope to override the binding. This works, but I was wondering if there was some way to avoid the function. I figured it's possible that you can bind the value of the input and have it automatically update my <TopBar> component binding... maybe?

  6. The preload method gives me access to params. What I want to know if there is some way for me to get access to params.slug without the preload function.

What would be really cool is to have some expert rewrite what I've done in the best possible way, possibly addressing some of my questions.

  1. Svelte will only iterate over array-like objects, because it's not possible to guarantee consistent behaviour with objects — it throws up various edge cases that are best solved at an app level. You can do this sort of thing, just using standard JavaScript idioms:

{{#each Object.values(info.attributes) as attr}}
  <p>{{attr.description}} ...</p>
{{/each}}

<!-- or, if you need the key as well -->
{{#each Object.entries(info.attributes) as [key, value]}}
  <p>{{attr.description}} ...</p>
{{/each}}

  1. Not aware of a direct angular-translate equivalent, but a straightforward i18n solution is to fetch some JSON in preload:

preload({ params, query }) {
  return fetch(`/i18n/${locale}.json`)
    .then(r => r.json())
    .then(dict => {
      return { dict };
    });
}

Then, you can reference things like {{dict["hello"]}} in your template. A more sophisticated solution would only load the strings necessary for the current page, and would cache everything etc, but the basic idea is the same.

  1. I guess you could do this:

// app/client.js (assuming Sapper >= 0.7)
import COMPONENTS from './config/components.json';
window.COMPONENTS = COMPONENTS;

// app/server.js
import COMPONENTS from './config/components.json';
global.COMPONENTS = COMPONENTS;

Importing isn't that bad though! It's good for a module's dependencies to be explicit.

  1. You can use the resolve.modules field in your webpack configs: https://webpack.js.org/configuration/resolve/#resolve-modules

  2. This would be a good place to use two-way binding:

{{#each Object.values(info.attributes) as attr}}
  <p>{{attr.description}} <input bind:value=organization_name /></p>
{{/each}}

  1. Yep, the params object is always available in your pages (not nested components, unless you pass the prop down, but all your top-level components like routes/whatever/[slug].html) — so you can reference it in templates as {{params.slug}}, or inside lifecycle hooks and methods as this.get('params').slug, whether or not a given component uses preload.