gpt4 book ai didi

api - 如何从 ember 中的子组件范围访问父组件范围?

转载 作者:行者123 更新时间:2023-12-04 18:43:07 25 4
gpt4 key购买 nike

我很好奇这是否可能在 Ember 中。这在 Angular 中很容易做到( plunkr: http://plnkr.co/edit/O2e0ukyXdKMs4FcgKGmX?p=preview ):

目标是为 api 消费者制作一个易于使用、通用、可重复使用的 Accordion api。

我希望调用者能够使用的 api 是这样的(就像 angular api 一样):

{{#ember-accordion listOfAccordionPaneObjects=model}}

{{#ember-accordion-heading}}
heading template html {{accordionPaneObject.firstName}}
{{/ember-accordion-heading}}

{{#ember-accordion-body}}
this is the accordion body {{accordionPaneObject.lastName}}
{{/ember-accordion-body}}

{{/ember-accordion}}

这是我使用 Angular 编写的一个工作示例:
<!doctype html>
<html ng-app="angular-accordion">
<head>
<style>
.angular-accordion-header {
background-color: #999;
color: #ffffff;
padding: 10px;
margin: 0;
line-height: 14px;
-webkit-border-top-left-radius: 5px;
-webkit-border-top-right-radius: 5px;
-moz-border-radius-topleft: 5px;
-moz-border-radius-topright: 5px;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
cursor: pointer;
text-decoration: none;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
}

.angular-accordion-container {
height: 100%;
width: 100%;
}

.angular-accordion-pane {
padding: 2px;
}

.angularaccordionheaderselected {
background-color: #bbb;
color: #333;
font-weight: bold;
}

.angular-accordion-header:hover {
text-decoration: underline !important;
}

.angularaccordionheaderselected:hover {
text-decoration: underline !important;
}

.angular-accordion-pane-content {
padding: 5px;
overflow-y: auto;
border-left: 1px solid #bbb;
border-right: 1px solid #bbb;
border-bottom: 1px solid #bbb;
-webkit-border-bottom-left-radius: 5px;
-webkit-border-bottom-right-radius: 5px;
-moz-border-radius-bottomleft: 5px;
-moz-border-radius-bottomright: 5px;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}

.angulardisabledpane {
opacity: .2;
}
</style>
</head>
<body style="margin: 0;">


<div style="height: 90%; width: 100%; margin: 0;" ng-controller="outerController">

<angular-accordion list-of-accordion-pane-objects="outerControllerData">
<pane>
<pane-header>Header {{accordionPaneObject}}</pane-header>
<pane-content>Content {{accordionPaneObject}}</pane-content>
</pane>
</angular-accordion>

</div>

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.1/angular.js"></script>
<script>
angular.module('angular-accordion', [])
.directive('angularAccordion', function() {
var template = '';

return {
restrict: 'E',
transclude: true,
replace: true,
template: '<div>' +
'<div ng-transclude class="angular-accordion-container" ng-repeat="accordionPaneObject in listOfAccordionPaneObjects"></div>' +
'</div>',
controller: ['$scope', function($scope) {
var panes = [];

this.addPane = function(pane) {
panes.push(pane);
};
}],
scope: {
listOfAccordionPaneObjects: '='
}
};
})
.directive('pane', function() {
return {
restrict: 'E',
transclude: true,
replace: true,
template: '<div ng-transclude class="angular-accordion-pane"></div>'
};
})
.directive('paneHeader', function() {
return {
restrict: 'E',
require: '^angularAccordion',
transclude: true,
replace: true,
link: function(scope, iElement, iAttrs, controller) {
controller.addPane(scope);

scope.toggle = function() {
scope.expanded = !scope.expanded;
};
},
template: '<div ng-transclude class="angular-accordion-header" ng-click="toggle()"></div>'
};
})
.directive('paneContent', function() {
return {
restrict: 'EA',
require: '^paneHeader',
transclude: true,
replace: true,
template: '<div ng-transclude class="angular-accordion-pane-content" ng-show="expanded"></div>'
};
})
.controller('outerController', ['$scope', function($scope) {
$scope.outerControllerData = [1, 2, 3];
}]);
</script>
</body>
</html>

这就是我对 ember 做同样的事情的地方:

索引.html
<!DOCTYPE html>
<html>
<body>
<script src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.1.9/require.js" data-main="main.js"></script>
</body>
</html>

main.js
require.config({
paths: {
'ember': 'bower_components/ember/ember',
'handlebars': 'bower_components/handlebars/handlebars',
'jquery': 'bower_components/jquery/jquery',
'text': 'bower_components/requirejs-text/text'
},
shim: {
ember: {
deps: ['jquery', 'handlebars'],
exports: 'Ember'
}
}
});

define(function(require) {
var Ember = require('ember'),
EmberAccordionComponent = require('src/EmberAccordionComponent'),
EmberAccordionTemplate = require('text!templates/ember-accordion.hbs'),
EmberAccordionHeaderTemplate = require('text!templates/ember-accordion-header.hbs'),
EmberAccordionBodyTemplate = require('text!templates/ember-accordion-body.hbs'),
ApplicationTemplate = require('text!templates/application.hbs'),
IndexTemplate = require('text!templates/index.hbs');

var App = Ember.Application.create({
LOG_STACKTRACE_ON_DEPRECATION : true,
LOG_BINDINGS : true,
LOG_TRANSITIONS : true,
LOG_TRANSITIONS_INTERNAL : true,
LOG_VIEW_LOOKUPS : true,
LOG_ACTIVE_GENERATION : true
});

Ember.TEMPLATES = {};
Ember.TEMPLATES['application'] = Ember.Handlebars.compile(ApplicationTemplate);
Ember.TEMPLATES['index'] = Ember.Handlebars.compile(IndexTemplate);
Ember.TEMPLATES['components/ember-accordion'] = Ember.Handlebars.compile(EmberAccordionTemplate);
Ember.TEMPLATES['components/ember-accordion-header'] = Ember.Handlebars.compile(EmberAccordionHeaderTemplate);
Ember.TEMPLATES['components/ember-accordion-body'] = Ember.Handlebars.compile(EmberAccordionBodyTemplate);

App.EmberAccordionComponent = EmberAccordionComponent;

App.IndexRoute = Ember.Route.extend({
model: function() {
return [
{
name: 'Bob'
},
{
name: 'Jill'
}]
}
})
});

EmberAccordionComponent.js
define(function(require) {
require('ember');

var EmberAccordionComponent = Ember.Component.extend({});

return EmberAccordionComponent;
});

应用程序.hbs
{{outlet}}

ember-accordion-header.hbs
<div style="color: blue;">
{{yield}}
</div>

ember- Accordion -body.hbs
<div style="color: green;">
{{yield}}
</div>

索引.hbs
{{#ember-accordion listOfAccordionPaneObjects=model}}
{{#ember-accordion-header}}
{{log this.constructor}}
{{log this}}
Header {{accordionPaneObject.name}}
{{/ember-accordion-header}}
{{#ember-accordion-body}}
Body {{accordionPaneObject.name}}
{{/ember-accordion-body}}
{{/ember-accordion}}

ember- Accordion .hbs
{{#each accordionPaneObject in listOfAccordionPaneObjects}}
{{yield}}
{{/each}}

--

这很难调试。所以放入:
{{log this.constructor}}

和:
{{log this}}

进入:
{{#ember-accordion-header}}

输出以下内容:
  • Class.model = 未定义(为什么?)
  • Ember.ArrayController

  • 我已尝试按照本文的建议覆盖 Ember.Component 的私有(private) _yield 方法( http://www.thesoftwaresimpleton.com/blog/2013/11/21/component-block/ ):
    var EmberAccordionHeaderComponent = Ember.Component.extend({
    _yield: function(context, options) {
    var get = Ember.get,
    view = options.data.view,
    parentView = this._parentView,
    template = get(this, 'template');

    if (template) {
    Ember.assert("A Component must have a parent view in order to yield.", parentView);
    view.appendChild(Ember.View, {
    isVirtual: true,
    tagName: '',
    _contextView: parentView,
    template: template,
    context: get(view, 'context'), // the default is get(parentView, 'context'),
    controller: get(view, 'controller'), // the default is get(parentView, 'context'),
    templateData: { keywords: parentView.cloneKeywords() }
    });
    }
    }
    });

    但是当我这样做时,我仍然无法在我的子组件范围内访问 Accordion PaneObject,我的 {{log this.constructor}} 现在指向:.EmberAccordionHeaderComponent

    所以看起来我到了某个地方,我只需要再上一层。

    当我尝试在 EmberAccordionHeaderComponent.js 中使用此代码时:
    var EmberAccordionHeaderComponent = Ember.Component.extend({
    _yield: function(context, options) {
    var get = Ember.get,
    view = options.data.view,
    parentView = this._parentView,
    grandParentView = this._parentView._parentView,
    template = get(this, 'template');

    if (template) {
    Ember.assert("A Component must have a parent view in order to yield.", parentView);
    view.appendChild(Ember.View, {
    isVirtual: true,
    tagName: '',
    _contextView: parentView,
    template: template,
    context: get(grandParentView, 'context'), // the default is get(parentView, 'context'),
    controller: get(grandParentView, 'controller'), // the default is get(parentView, 'context'),
    templateData: { keywords: parentView.cloneKeywords() }
    });
    }
    }
    });

    我仍然无法访问accordionPaneObject,但现在我看到 {{log this.constructor}} 输出 .EmberAccordionComponent。所以看起来我在正确的范围内,但数据仍然没有绑定(bind)。

    有趣的是,如果我在重写的 _yield 中使用任何这些重新分配上下文和 Controller 的变体,我可以使用以下命令访问控制台中的数据:
    this._parentView._context.content

    最佳答案

    我用一些评论更新了你的代码,请看一下 http://emberjs.jsbin.com/ivOyiZa/1/edit .

    Javascript

    App = Ember.Application.create();

    App.IndexRoute = Ember.Route.extend({
    model: function() {
    return [
    { head: "foo head", body: "foo body " },
    { head: "bar head", body: "bar body " },
    { head: "ya head", body: "yo body " }
    ];
    }
    });

    App.EmberAccordionComponent = Ember.Component.extend({
    // each accordion header/body item, will have a instance of that view.
    // so we can isolate the expanded state for each accordion header/body
    emberAccordionItemView: Ember.View.extend({
    expanded: false
    }),
    _yield: function(context, options) {
    var get = Ember.get,
    view = options.data.view,
    parentView = this._parentView,
    template = get(this, 'template');

    if (template) {
    Ember.assert("A Component must have a parent view in order to yield.", parentView);
    view.appendChild(Ember.View, {
    isVirtual: true,
    tagName: '',
    _contextView: parentView,
    template: template,
    context: get(view, 'context'), // the default is get(parentView, 'context'),
    controller: get(view, 'controller'), // the default is get(parentView, 'context'),
    templateData: { keywords: parentView.cloneKeywords() }
    });
    }
    }
    });

    App.EmberAccordionHeaderComponent = Ember.Component.extend({
    classNames: ['ember-accordion-header'],
    click: function() {
    // here we toggle the emberAccordionItemView.expanded property
    this.toggleProperty('parentView.expanded');
    }
    });

    模板
      <script type="text/x-handlebars" data-template-name="index">
    {{#ember-accordion listOfAccordionPaneObjects=model}}
    {{#ember-accordion-header}}
    {{head}} <!-- each object passed in listOfAccordionPaneObjects=model can be accessed here -->
    {{/ember-accordion-header}}
    {{#ember-accordion-body}}
    {{body}} <!-- each object passed in listOfAccordionPaneObjects=model can be accessed here -->
    {{/ember-accordion-body}}
    {{/ember-accordion}}
    </script>

    <script type="text/x-handlebars" data-template-name="components/ember-accordion">
    {{#each listOfAccordionPaneObjects itemViewClass="view.emberAccordionItemView"}}
    <div class="ember-accordion-container">
    <div class="ember-accordion-pane">
    {{yield}}
    </div>
    </div>
    {{/each}}
    </script>

    <script type="text/x-handlebars" data-template-name="components/ember-accordion-header">
    {{yield}}
    </script>

    <script type="text/x-handlebars" data-template-name="components/ember-accordion-body">
    <!-- when EmberAccordionHeaderComponent.click is called, the expanded property change and the content can be visible or not, based on expanded truth -->
    {{#if parentView.expanded}}
    <div class="ember-accordion-pane-content">
    {{yield}}
    </div>
    {{/if}}
    </script>

    CSS
    .ember-accordion-header {
    background-color: #999;
    color: #ffffff;
    padding: 10px;
    margin: 0;
    line-height: 14px;
    -webkit-border-top-left-radius: 5px;
    -webkit-border-top-right-radius: 5px;
    -moz-border-radius-topleft: 5px;
    -moz-border-radius-topright: 5px;
    border-top-left-radius: 5px;
    border-top-right-radius: 5px;
    cursor: pointer;
    text-decoration: none;
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-size: 14px;
    }

    .ember-accordion-container {
    height: 100%;
    width: 100%;
    }

    .ember-accordion-pane {
    padding: 2px;
    }

    .emberaccordionheaderselected {
    background-color: #bbb;
    color: #333;
    font-weight: bold;
    }

    .ember-accordion-header:hover {
    text-decoration: underline !important;
    }

    .emberaccordionheaderselected:hover {
    text-decoration: underline !important;
    }

    .ember-accordion-pane-content {
    padding: 5px;
    overflow-y: auto;
    border-left: 1px solid #bbb;
    border-right: 1px solid #bbb;
    border-bottom: 1px solid #bbb;
    -webkit-border-bottom-left-radius: 5px;
    -webkit-border-bottom-right-radius: 5px;
    -moz-border-radius-bottomleft: 5px;
    -moz-border-radius-bottomright: 5px;
    border-bottom-left-radius: 5px;
    border-bottom-right-radius: 5px;
    }

    .emberdisabledpane {
    opacity: .2;
    }

    关于api - 如何从 ember 中的子组件范围访问父组件范围?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20158948/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com