[源码分析]Yii2如何加载前端资源

技巧库 · ppker · 于 4年前 发布 · 4391 次阅读

前言

YII2到底是如何加载前端资源的呢 简单的分析下框架的内部实现过程,便于举一反三。
个人认为好多复杂的东西其实都很简单 把大象放进冰箱只需要三步即可
这里也是分了三步

第一步

AppAsset::register($this); // view -> assetBundles
BowerAsset::register($this);

这一步的作用主要是 把AppAset 这类对象注入到 View类的 assetBundles 中进行保存,
方便后续的调用

public function registerAssetBundle($name, $position = null)
    {
        if (!isset($this->assetBundles[$name])) {
            $am = $this->getAssetManager();
            $bundle = $am->getBundle($name);
            $this->assetBundles[$name] = false;
            // register dependencies
            $pos = isset($bundle->jsOptions['position']) ? $bundle->jsOptions['position'] : null;
            foreach ($bundle->depends as $dep) {
                $this->registerAssetBundle($dep, $pos);
            }
            $this->assetBundles[$name] = $bundle; // 此处进行注入
        } elseif ($this->assetBundles[$name] === false) {
            throw new InvalidConfigException("A circular dependency is detected for bundle '$name'.");
        } else {
            $bundle = $this->assetBundles[$name];
        }

        if ($position !== null) {
            $pos = isset($bundle->jsOptions['position']) ? $bundle->jsOptions['position'] : null;
            if ($pos === null) {
                $bundle->jsOptions['position'] = $pos = $position;
            } elseif ($pos > $position) {
                throw new InvalidConfigException("An asset bundle that depends on '$name' has a higher javascript file position configured than '$name'.");
            }
            // update position for all dependencies
            foreach ($bundle->depends as $dep) {
                $this->registerAssetBundle($dep, $pos);
            }
        }

        return $bundle;
    }
    
另外
$this->registerJs( // view -> js
    'Config = {emojiBaseUrl: "' . $emojify->baseUrl . '"};',
    \yii\web\View::POS_HEAD
);
这里其实就是把 你自己的js代码 注入到 View类的 js变量中。 跟上面的模式是一样的

第二步

<?php $this->head() ?>
<?php $this->endBody() ?>
第二步主要是进行标记钩子 方便我后面对此处进行进一步处理 进行替换
public function head()
{
    echo self::PH_HEAD;
}

public function endBody()
{
    $this->trigger(self::EVENT_END_BODY);
    echo self::PH_BODY_END; // 做上标记

    foreach (array_keys($this->assetBundles) as $bundle) {
        // kartik\icons\FontAwesomeAsset
        $this->registerAssetFiles($bundle);
    }
}
head() 没啥好说的
endBody() 除了trigger()和ehco 标记 下面那个foreach() 里面的函数

protected function registerAssetFiles($name)
    {
        if (!isset($this->assetBundles[$name])) {
            return;
        }
        $bundle = $this->assetBundles[$name];
        if ($bundle) {
            foreach ($bundle->depends as $dep) {
                $this->registerAssetFiles($dep);
            }
            $bundle->registerAssetFiles($this); // 把css jss 文件都放入 view 全局变量中
        }
        unset($this->assetBundles[$name]);
    }

主要就是把 css jss 文件都放入 view 全局变量中

第三步

<?php $this->endPage() ?>

public function endPage($ajaxMode = false)
    {
        $this->trigger(self::EVENT_END_PAGE);

        $content = ob_get_clean();

        echo strtr($content, [
            self::PH_HEAD => $this->renderHeadHtml(),
            self::PH_BODY_BEGIN => $this->renderBodyBeginHtml(),
            self::PH_BODY_END => $this->renderBodyEndHtml($ajaxMode),
        ]);
        $this->clear();
    }
    
看到那个strtr 函数了么? 这里就是把你的css js 文件根据 key的代表的位置 进行替换到第二步中的钩子标记处
这样 css js 就注入到指定的位置了

总结

一生二 二生三 三生万物,再复杂的事物都是有3步过来的。请记住把大象放冰箱只需要三步,学习YII2只需要三步。哈哈

本文由 ppker 创作,采用 知识共享署名 3.0 中国大陆许可协议 进行许可。 可自由转载、引用,但需署名作者且注明文章出处。

共收到 3 条回复 GetYii asset
forecho#14年前 0 个赞

赞,分享的很不错,但是排版还有待改善,学好 Markdown 排版,不要滥用格式,重新排版给你加精。

排版教程:https://getyii.com/markdown

ppker#24年前 0 个赞

@forecho #1楼 O(∩_∩)O 我喜欢在代码界面看文章

forecho#34年前 0 个赞

@ppker #2楼 也可以啊,用注释的方式写说明

添加回复 (需要登录)
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册