引言
在当今前后端分离的大趋势下,仍然有一些前后端不分离的需求。因为boss考虑到webpack打包比较麻烦和耗时,使运维有一些问题,但是又无法舍弃vue数据绑定等棒棒哒功能,所以在前后端不分离的情况下,以yii+vue+element技术栈写项目的任务应运而生,而且这个任务给了我。
具体要求
- 能封装出各种组件,在php中调用
- 能进行一定程度的定制化
- 尽量用php写
头脑沙尘暴
- 对于第一个问题,我选择用yii中的自定义小部件去写,首先小部件是面向对象方式来重用视图代码,而且符和可配置的需求。
- 对于第二个问题,就是这个部件既可以传几个参数进行配置,又可以写一个完整的函数去覆盖。(十脸懵逼)
- 对于第三个问题,意思是尽量把代码写在controller里面,然后赋值给小部件。
第一版
第一版主要解决了一些基础问题,比如widget目录结构,vue引入,如何混合写php和js这样的问题。
-
涉及小部件的目录结构
Project └───assets │ └───AppAsset.php // 此处引入element,vue └───components | └───Form │ │ FormView.php // 部件视图文件 │ │ FormWidget.php │ └───web └───js └───conponents └─── form.js // 实例化vue 复制代码
-
具体代码
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'; } } 复制代码
-
使用,在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() ' ] ])?> 复制代码
-
第一版遇到的问题
- 小部件通信,比如有树小部件和表单小部件,我点击树的节点时,表单小部件需要更新,那么就要求树的vue实例中能操纵表单的vue实例
- methods的参数问题,如上面的代码,vue_form_method是遍历form_methods之后赋值给了vue的methods属性,但是这样遍历没办法指定参数。比如element的tree有一个事件node-click,默认传三个参数,这个没办法在 form_methods中指定。
- boss的一些新想法
- 广播,即页面所有组件都可以监听事件,事件发生后,对应监听该事件的组件可以做出相应反应
- 全局变量,比如两个组件引入同一变量,这个变量变化的时候,两个组件的数据也相应变化
-
解决方案
- 把vue实例赋值给一个变量,比如
var Tree = new Vue()
,然后其他组件可以用Tree.example_data来访问树的属性 - 用arguments,
var node = arguments[0]
来访问参数。当然我个人认为这不是很好的方法,但是没想出更好的解决办法 - 广播的问题,我写了一个event_bus小部件,这个小部件只是一个单纯的vue实例,每个部件用
EventBus.$on('click', function() {})
的方法监听事件,EventBus.$emit('click')
的方法触发事件就可以了。 - 当这个全局变量是一个对象或者是数组的时候,才可以在变量变化时,数据也变化
- 把vue实例赋值给一个变量,比如
to be continue...
所有评论(0)