yii2 多模板路径优先级加载view方式下- js和css 的解决

fecshop 使用了多模板view文件优先级加载,在view和layout文件比较容易解决

比较难弄的是js和css部分,用yii2提供的yii\web\AssetBundle; 做了很多尝试都没有解决,最后自己写了一个来最终实现多模板下   js和css,也根据模板路径优先级下载。

首先说一下多模板路径,下面有多个模板路径,按照优先级依次如下:

@appfront/theme/terry/theme01/

@fecshop/theme/base/front/

@fecshop/theme/base/base/

如果我要加载的view文件为   cms/index/index,  首先查看  @appfront/theme/terry/theme01/cms/index/index.php文件是否存在,如果不存在,则查看@fecshop/theme/base/front/cms/index/index.php,如果还不存在,则看文件@fecshop/theme/base/base/cms/index/index.php 是否存在,如果不存在则报错返回。

上面是多模板的思路,为了是解决view文件,在fecshop系统模板升级和用户二次开发模板的矛盾冲突。

现在我想要css和js也这样,通过优先级加载css和js,

下面是我的实现:定义组件配置  :

      
      'asset' => [
        'class' =>  'fecshop\services\page\Asset',
        # js config
        'jsOptions'	=> [
          # js config 1
          [
            'options' => [
              'position' =>  'POS_END',
            //	'condition'=> 'lt IE 9',
            ],
            'js'	=>[
              'js/jquery-3.0.0.min.js',
              'js/js.js',
            ],
          ],
          # js config 2
          [
            'options' => [
              'condition'=> 'lt IE 9',
            ],
            'js'	=>[
              'js/ie9js.js'
            ],
          ],
        ],
        # css config
        'cssOptions'	=> [
          # css config 1.
          [
            'css'	=>[
              'css/style.css',
              'css/ie.css',
            ],
          ],
          
          # css config 2.
          [
            'options' => [
              'condition'=> 'lt IE 9',
            ],
            'css'	=>[
              'css/ltie9.css',
            ],
            
          ],
          
        ],
        
        //'cssOptions' => [
        //	'condition'
        //],
        //'jsOptions' => [
        //	'position' =>  'POS_END',
        //]
        
      ],

2. 组件部分:

<?php
/**
 * FecShop file.
 *
 * @link http://www.fecshop.com/
 * @copyright Copyright (c) 2016 FecShop Software LLC
 * @license http://www.fecshop.com/license/
 */
namespace fecshop\services\page;
use Yii;

use yii\base\Component;
use yii\helpers\ArrayHelper;
use yii\helpers\Url;

/**
 * Breadcrumbs services
 * @author Terry Zhao <2358269014@qq.com>
 * @since 1.0
 extends AssetBundle
 */
class Asset extends Component
{
  public $cssOptions;
  public $jsOptions; 
  /**
   * 在模板路径下的相对文件夹。
   * 譬如模板路径为@fecshop/app/theme/base/front
   * 那么js,css路径默认为@fecshop/app/theme/base/front/assets
   */
  public $defaultDir = 'assets';
    /**
   * 文件路径默认放到模板路径下面的assets里面
   */
  public function register($view){
    $assetArr = [];
    $themeDir = Yii::$app->page->theme->getThemeDirArr();
    if( is_array($themeDir) && !empty($themeDir)){
      if( is_array($this->jsOptions) && !empty($this->jsOptions)){
        foreach($this->jsOptions as $jsOption){
          if( isset($jsOption['js']) && is_array($jsOption['js']) && !empty($jsOption['js'])){
      
            foreach($jsOption['js'] as $jsPath){
              foreach($themeDir as $dir){
                $dir = $dir.'/'.$this->defaultDir.'/';
                $jsAbsoluteDir = $dir.$jsPath;
                if(file_exists($jsAbsoluteDir)){
                    $assetArr[$dir]['jsOptions'][] = [
                    'js' 		=>  $jsPath,
                    'options' 	=>  $this->initOptions($jsOption['options']),
                  ];
                  break;
                }
              }
            }
          }
        }	
      }
      
      if( is_array($this->cssOptions) && !empty($this->cssOptions)){
        foreach($this->cssOptions as $cssOption){
          if( isset($cssOption['css']) && is_array($cssOption['css']) && !empty($cssOption['css'])){
            foreach($cssOption['css'] as $cssPath){		
              foreach($themeDir as $dir){
                $dir = $dir.'/'.$this->defaultDir.'/';
                $cssAbsoluteDir = $dir.$cssPath;
                if(file_exists($cssAbsoluteDir)){
                  $assetArr[$dir]['cssOptions'][] = [
                    'css' 		=>  $cssPath,
                    'options' 	=>  $this->initOptions($cssOption['options']),
                  ];
                  break;
                }
              }
            }
          }
        }	
      }
    }
    if(!empty($assetArr)){
      foreach($assetArr as $fileDir=>$as){
        $cssConfig = $as['cssOptions'];
        $jsConfig = $as['jsOptions'];
        $publishDir = $view->assetManager->publish($fileDir);
        if(!empty($jsConfig) && is_array($jsConfig)){
          foreach($jsConfig as $c){
            $view->registerJsFile($publishDir[1].'/'.$c['js'],$c['options']);
          }
        }
        if(!empty($cssConfig) && is_array($cssConfig)){
          foreach($cssConfig as $c){
            $view->registerCssFile($publishDir[1].'/'.$c['css'],$c['options']);
          }
        }
      }
    }
  }
  
  
  public function initOptions($options){
    if(isset($options['position'])){
      if($options['position'] == 'POS_HEAD'){
        $options['position'] =  \yii\web\View::POS_HEAD;
      }else if($options['position'] == 'POS_END'){
        $options['position'] =  \yii\web\View::POS_END;
      }
    }
    return $options;
  }
}












上面的 Yii::$app->page->theme->getThemeDirArr() 表示得到多模板路径数组。

在layout文件中使用

\Yii::$app->page->asset->register($this);

 

经过测试,可以在多个模板路径的assets下面查找js,找到后返回,找不到,继续到下一个模板路径中找js或者css文件。最后发布。

 

 

《yii2 多模板路径优先级加载view方式下- js和css 的解决》有3个想法

  1. 为什么不在 view 中去定义要加载的独有的 css 和 js 呢?这样用了哪个 view 文件就调用这个文件中指定的 css 和 js,通用的就放 layout。这个可以通过 AssetBundle 实现。

    1. 做产品也解决一个 产品升级,第三方插件,用户二次开发, 在文件升级的冲突的问题
      你先想想如何解决。
      然后在想为什么要这样做多模板路径优先级的功能。

  2. 你好,问一下如果想通过webpack来打包js和css文件,在这种情况下,怎么才能达到js和css的多目录优先覆盖打包功能呢?甚至css文件中还可能加载字体文件和图片文件。

    比如我有一个网站项目A,使用了webpack打包所有的resource。又有一个网站项目B,直接包装了A,php,模板什么的都可以通过继承、注入、多目录来解决掉,但是项目B如何直接使用已经在A里面实现过的所有css,js,其他资源呢? 甚至项目B只覆盖了A中的一个js文件,所有加载这个js的就会使用项目B中的,其他文件依然使用项目A的,最终打包好后被使用

admin进行回复 取消回复

电子邮件地址不会被公开。 必填项已用*标注