引言

在当今前后端分离的大趋势下,仍然有一些前后端不分离的需求。因为boss考虑到webpack打包比较麻烦和耗时,使运维有一些问题,但是又无法舍弃vue数据绑定等棒棒哒功能,所以在前后端不分离的情况下,以yii+vue+element技术栈写项目的任务应运而生,而且这个任务给了我。

具体要求

  1. 能封装出各种组件,在php中调用
  2. 能进行一定程度的定制化
  3. 尽量用php写

头脑沙尘暴

  1. 对于第一个问题,我选择用yii中的自定义小部件去写,首先小部件是面向对象方式来重用视图代码,而且符和可配置的需求。
  2. 对于第二个问题,就是这个部件既可以传几个参数进行配置,又可以写一个完整的函数去覆盖。(十脸懵逼)
  3. 对于第三个问题,意思是尽量把代码写在controller里面,然后赋值给小部件。

第一版

第一版主要解决了一些基础问题,比如widget目录结构,vue引入,如何混合写php和js这样的问题。

  1. 涉及小部件的目录结构

    Project
    └───assets
    │       └───AppAsset.php // 此处引入element,vue
    └───components
    |    └───Form
    │         │   FormView.php    // 部件视图文件
    │         │   FormWidget.php 
    │   
    └───web
        └───js
            └───conponents
                └─── form.js // 实例化vue
    复制代码
  2. 具体代码

    AppAsset.php

        <?php
        namespace app\assets;
        use yii\web\AssetBundle;
        class AppAsset extends AssetBundle
        {
            public $basePath = '@webroot';
            public $baseUrl = '@web';
            public $css = [
                'css/site.css',
                'css/element-ui/index.css',
            ];
            public $js = [
                'js/vue/vue.js',
                'js/element-ui/index.js',
            ];
            public $depends = [
                'yii\web\YiiAsset',
                'yii\bootstrap\BootstrapAsset',
            ];
        
        }
    复制代码

    FormView.php

    <?php
    use app\components\form\FormAsset;
    FormAsset::register($this);
    
    $this->registerJsFile('@web/js/components/form.js', ['position'=> \yii\web\View::POS_END, 'depends' => @app\assets\AppAsset::ClassName()]);  
    ?>
    <div id="form">
       
    </div>
    <script type='text/javascript'>
    var vue_form_template = <?=json_encode($form_template)?>;
    var vue_form_data = <?=json_encode($form_data)?>;
    var vue_form_mounted= <?=json_encode($form_mounted)?>
    
    var form_temp_methods= <?=json_encode($form_methods)?>;
    var vue_form_method = {};
    
    function generateMethods() {
        for (let key in form_temp_methods) {
            vue_form_method[key] = function() {
                // 参数默认用arguments
                console.log(arguments);
                eval(form_temp_methods[key])
            }
        };
    }
    generateMethods()
    </script>
    复制代码

    FormWidget

        <?php
        namespace app\components\form;
        use yii\base\Widget;
        use yii\helpers\Html;
        use app\assets\AppAsset;
        
        
        class FormWidget extends Widget
        {
            public $form_template = '';
        
            public $form_data = [];
        
            public $form_mounted;
        
            public $form_methods;
        
            public function init()
            {
                
            }
        
            public function run()
            {   
                return $this->render('FormView',[
                    'form_template'=>$this->form_template,
                    'form_data'=>$this->form_data,
                    'form_mounted'=>$this->form_mounted,
                    'form_methods'=>$this->form_methods,
                ]);
            }
        
            public function getViewPath() // 这个函数可以定义部件view的路径
            {
                return '@app/components/form'; 
            }
        }
    复制代码
  3. 使用,在index.php

        <?=FormWidget::widget([
            // controller中传入的html,类似<el-button></el-button>
            'form_template' => $form_template, 
            'form_data' => $form_data,
            'form_mounted' => $form_mounted,
            'form_methods' => [
                'closeForm' => '
                    Table.table_span = 20;
                    this.form_data.form_is_show = false;
                ',
                'saveForm' => '
                    this.closeForm()
                '
            ]
        ])?>
    复制代码
  4. 第一版遇到的问题

    • 小部件通信,比如有树小部件和表单小部件,我点击树的节点时,表单小部件需要更新,那么就要求树的vue实例中能操纵表单的vue实例
    • methods的参数问题,如上面的代码,vue_form_method是遍历form_methods之后赋值给了vue的methods属性,但是这样遍历没办法指定参数。比如element的tree有一个事件node-click,默认传三个参数,这个没办法在 form_methods中指定。
    • boss的一些新想法
      • 广播,即页面所有组件都可以监听事件,事件发生后,对应监听该事件的组件可以做出相应反应
      • 全局变量,比如两个组件引入同一变量,这个变量变化的时候,两个组件的数据也相应变化
  5. 解决方案

    • 把vue实例赋值给一个变量,比如var Tree = new Vue(),然后其他组件可以用Tree.example_data来访问树的属性
    • 用arguments,var node = arguments[0]来访问参数。当然我个人认为这不是很好的方法,但是没想出更好的解决办法
    • 广播的问题,我写了一个event_bus小部件,这个小部件只是一个单纯的vue实例,每个部件用EventBus.$on('click', function() {})的方法监听事件,EventBus.$emit('click')的方法触发事件就可以了。
    • 当这个全局变量是一个对象或者是数组的时候,才可以在变量变化时,数据也变化

to be continue...

Logo

前往低代码交流专区

更多推荐